aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuriy Piskarev <yuriy.piskarev@gmail.com>2023-08-24 14:16:17 +0300
committerGitHub <noreply@github.com>2023-08-24 14:16:17 +0300
commitae406c7b49a72de24d81fd74386d9638342c90ee (patch)
tree6fbcf557375b98e926c78af9c757e62c79d72a1b
parent56ff656c908b19feb2fa3dcffa48cc3bcdfe9b3b (diff)
parent9aeedc90da24848ff97227d6f281eb4d1e1506ef (diff)
downloadtrackermap-server-ae406c7b49a72de24d81fd74386d9638342c90ee.tar.gz
trackermap-server-ae406c7b49a72de24d81fd74386d9638342c90ee.tar.bz2
trackermap-server-ae406c7b49a72de24d81fd74386d9638342c90ee.zip
Merge branch 'traccar:master' into master
-rw-r--r--.github/CONTRIBUTING.md2
-rw-r--r--.github/workflows/gradle.yml12
-rw-r--r--.github/workflows/release.yml61
-rw-r--r--.gitignore2
-rw-r--r--build.gradle102
-rw-r--r--debug.xml7
-rw-r--r--gradle/checkstyle.xml10
-rw-r--r--gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--schema/changelog-4.0-clean.xml8
-rw-r--r--schema/changelog-5.0.xml (renamed from schema/changelog-4.16.xml)10
-rw-r--r--schema/changelog-5.1.xml37
-rw-r--r--schema/changelog-5.2.xml21
-rw-r--r--schema/changelog-5.3.xml41
-rw-r--r--schema/changelog-5.4.xml55
-rw-r--r--schema/changelog-5.5.xml15
-rw-r--r--schema/changelog-5.6.xml73
-rw-r--r--schema/changelog-5.7.xml25
-rw-r--r--schema/changelog-5.8.xml18
-rw-r--r--schema/changelog-5.9.xml27
-rw-r--r--schema/changelog-master.xml12
-rw-r--r--setup/cloud-init.yaml29
-rw-r--r--setup/default.xml18
-rw-r--r--setup/environment.sh27
-rwxr-xr-xsetup/package.sh46
-rw-r--r--setup/traccar.iss2
-rw-r--r--src/main/java/org/traccar/BasePipelineFactory.java50
-rw-r--r--src/main/java/org/traccar/BaseProtocol.java21
-rw-r--r--src/main/java/org/traccar/BaseProtocolDecoder.java177
-rw-r--r--src/main/java/org/traccar/BaseProtocolEncoder.java66
-rw-r--r--src/main/java/org/traccar/Context.java416
-rw-r--r--src/main/java/org/traccar/ExtendedObjectDecoder.java34
-rw-r--r--src/main/java/org/traccar/LifecycleObject.java2
-rw-r--r--src/main/java/org/traccar/Main.java46
-rw-r--r--src/main/java/org/traccar/MainEventHandler.java81
-rw-r--r--src/main/java/org/traccar/MainModule.java474
-rw-r--r--src/main/java/org/traccar/PositionForwardingHandler.java141
-rw-r--r--src/main/java/org/traccar/ServerManager.java38
-rw-r--r--src/main/java/org/traccar/TrackerClient.java20
-rw-r--r--src/main/java/org/traccar/TrackerServer.java22
-rw-r--r--src/main/java/org/traccar/WebDataHandler.java310
-rw-r--r--src/main/java/org/traccar/api/AsyncSocket.java34
-rw-r--r--src/main/java/org/traccar/api/AsyncSocketServlet.java37
-rw-r--r--src/main/java/org/traccar/api/BaseObjectResource.java188
-rw-r--r--src/main/java/org/traccar/api/BaseResource.java16
-rw-r--r--src/main/java/org/traccar/api/CorsResponseFilter.java22
-rw-r--r--src/main/java/org/traccar/api/DateParameterConverterProvider.java4
-rw-r--r--src/main/java/org/traccar/api/ExtendedObjectResource.java61
-rw-r--r--src/main/java/org/traccar/api/MediaFilter.java68
-rw-r--r--src/main/java/org/traccar/api/ResourceErrorHandler.java6
-rw-r--r--src/main/java/org/traccar/api/SimpleObjectResource.java42
-rw-r--r--src/main/java/org/traccar/api/resource/AttributeResource.java80
-rw-r--r--src/main/java/org/traccar/api/resource/CalendarResource.java8
-rw-r--r--src/main/java/org/traccar/api/resource/CommandResource.java153
-rw-r--r--src/main/java/org/traccar/api/resource/DeviceResource.java179
-rw-r--r--src/main/java/org/traccar/api/resource/DriverResource.java8
-rw-r--r--src/main/java/org/traccar/api/resource/EventResource.java36
-rw-r--r--src/main/java/org/traccar/api/resource/GeofenceResource.java8
-rw-r--r--src/main/java/org/traccar/api/resource/GroupResource.java8
-rw-r--r--src/main/java/org/traccar/api/resource/MaintenanceResource.java8
-rw-r--r--src/main/java/org/traccar/api/resource/NotificationResource.java66
-rw-r--r--src/main/java/org/traccar/api/resource/OrderResource.java8
-rw-r--r--src/main/java/org/traccar/api/resource/PasswordResource.java85
-rw-r--r--src/main/java/org/traccar/api/resource/PermissionsResource.java89
-rw-r--r--src/main/java/org/traccar/api/resource/PositionResource.java132
-rw-r--r--src/main/java/org/traccar/api/resource/ReportResource.java335
-rw-r--r--src/main/java/org/traccar/api/resource/ServerResource.java122
-rw-r--r--src/main/java/org/traccar/api/resource/SessionResource.java127
-rw-r--r--src/main/java/org/traccar/api/resource/StatisticsResource.java26
-rw-r--r--src/main/java/org/traccar/api/resource/UserResource.java104
-rw-r--r--src/main/java/org/traccar/api/security/LoginService.java129
-rw-r--r--src/main/java/org/traccar/api/security/PermissionsService.java225
-rw-r--r--src/main/java/org/traccar/api/security/SecurityRequestFilter.java70
-rw-r--r--src/main/java/org/traccar/api/security/ServiceAccountUser.java (renamed from src/main/java/org/traccar/database/MaintenancesManager.java)19
-rw-r--r--src/main/java/org/traccar/api/security/UserSecurityContext.java2
-rw-r--r--src/main/java/org/traccar/api/signature/CryptoManager.java103
-rw-r--r--src/main/java/org/traccar/api/signature/KeystoreModel.java44
-rw-r--r--src/main/java/org/traccar/api/signature/TokenManager.java77
-rw-r--r--src/main/java/org/traccar/broadcast/BaseBroadcastService.java118
-rw-r--r--src/main/java/org/traccar/broadcast/BroadcastInterface.java45
-rw-r--r--src/main/java/org/traccar/broadcast/BroadcastMessage.java85
-rw-r--r--src/main/java/org/traccar/broadcast/BroadcastService.java23
-rw-r--r--src/main/java/org/traccar/broadcast/MulticastBroadcastService.java112
-rw-r--r--src/main/java/org/traccar/broadcast/NullBroadcastService.java (renamed from src/main/java/org/traccar/api/ObjectMapperProvider.java)24
-rw-r--r--src/main/java/org/traccar/broadcast/RedisBroadcastService.java130
-rw-r--r--src/main/java/org/traccar/config/Config.java45
-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/KeyType.java2
-rw-r--r--src/main/java/org/traccar/config/Keys.java1308
-rw-r--r--src/main/java/org/traccar/database/AttributesManager.java36
-rw-r--r--src/main/java/org/traccar/database/BaseObjectManager.java178
-rw-r--r--src/main/java/org/traccar/database/CommandsManager.java221
-rw-r--r--src/main/java/org/traccar/database/ConnectionManager.java216
-rw-r--r--src/main/java/org/traccar/database/DataManager.java276
-rw-r--r--src/main/java/org/traccar/database/DeviceLookupService.java141
-rw-r--r--src/main/java/org/traccar/database/DeviceManager.java471
-rw-r--r--src/main/java/org/traccar/database/DriversManager.java100
-rw-r--r--src/main/java/org/traccar/database/ExtendedObjectManager.java143
-rw-r--r--src/main/java/org/traccar/database/GeofenceManager.java66
-rw-r--r--src/main/java/org/traccar/database/GroupsManager.java83
-rw-r--r--src/main/java/org/traccar/database/IdentityManager.java50
-rw-r--r--src/main/java/org/traccar/database/LdapProvider.java2
-rw-r--r--src/main/java/org/traccar/database/MailManager.java151
-rw-r--r--src/main/java/org/traccar/database/MediaManager.java19
-rw-r--r--src/main/java/org/traccar/database/NotificationManager.java195
-rw-r--r--src/main/java/org/traccar/database/OpenIdProvider.java203
-rw-r--r--src/main/java/org/traccar/database/PermissionsManager.java528
-rw-r--r--src/main/java/org/traccar/database/SimpleObjectManager.java100
-rw-r--r--src/main/java/org/traccar/database/StatisticsManager.java44
-rw-r--r--src/main/java/org/traccar/database/UsersManager.java93
-rw-r--r--src/main/java/org/traccar/forward/AmqpClient.java58
-rw-r--r--src/main/java/org/traccar/forward/EventData.java78
-rw-r--r--src/main/java/org/traccar/forward/EventForwarder.java (renamed from src/main/java/org/traccar/database/ManagableObjects.java)15
-rw-r--r--src/main/java/org/traccar/forward/EventForwarderAmqp.java48
-rw-r--r--src/main/java/org/traccar/forward/EventForwarderJson.java68
-rw-r--r--src/main/java/org/traccar/forward/EventForwarderKafka.java58
-rw-r--r--src/main/java/org/traccar/forward/EventForwarderMqtt.java100
-rw-r--r--src/main/java/org/traccar/forward/NetworkForwarder.java77
-rw-r--r--src/main/java/org/traccar/forward/PositionData.java45
-rw-r--r--src/main/java/org/traccar/forward/PositionForwarder.java20
-rw-r--r--src/main/java/org/traccar/forward/PositionForwarderAmqp.java48
-rw-r--r--src/main/java/org/traccar/forward/PositionForwarderJson.java86
-rw-r--r--src/main/java/org/traccar/forward/PositionForwarderKafka.java58
-rw-r--r--src/main/java/org/traccar/forward/PositionForwarderRedis.java50
-rw-r--r--src/main/java/org/traccar/forward/PositionForwarderUrl.java166
-rw-r--r--src/main/java/org/traccar/forward/ResultHandler.java20
-rw-r--r--src/main/java/org/traccar/geocoder/BanGeocoder.java9
-rw-r--r--src/main/java/org/traccar/geocoder/BingMapsGeocoder.java9
-rw-r--r--src/main/java/org/traccar/geocoder/FactualGeocoder.java7
-rw-r--r--src/main/java/org/traccar/geocoder/GeoapifyGeocoder.java9
-rw-r--r--src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java8
-rw-r--r--src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java7
-rw-r--r--src/main/java/org/traccar/geocoder/Geocoder.java4
-rw-r--r--src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java7
-rw-r--r--src/main/java/org/traccar/geocoder/GoogleGeocoder.java11
-rw-r--r--src/main/java/org/traccar/geocoder/HereGeocoder.java8
-rw-r--r--src/main/java/org/traccar/geocoder/JsonGeocoder.java28
-rw-r--r--src/main/java/org/traccar/geocoder/LocationIqGeocoder.java (renamed from src/main/java/org/traccar/DeviceSession.java)29
-rw-r--r--src/main/java/org/traccar/geocoder/MapQuestGeocoder.java9
-rw-r--r--src/main/java/org/traccar/geocoder/MapTilerGeocoder.java9
-rw-r--r--src/main/java/org/traccar/geocoder/MapboxGeocoder.java11
-rw-r--r--src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java9
-rw-r--r--src/main/java/org/traccar/geocoder/NominatimGeocoder.java8
-rw-r--r--src/main/java/org/traccar/geocoder/OpenCageGeocoder.java10
-rw-r--r--src/main/java/org/traccar/geocoder/PositionStackGeocoder.java9
-rw-r--r--src/main/java/org/traccar/geocoder/TestGeocoder.java36
-rw-r--r--src/main/java/org/traccar/geocoder/TomTomGeocoder.java9
-rw-r--r--src/main/java/org/traccar/geofence/GeofenceCircle.java4
-rw-r--r--src/main/java/org/traccar/geofence/GeofenceGeometry.java5
-rw-r--r--src/main/java/org/traccar/geofence/GeofencePolygon.java4
-rw-r--r--src/main/java/org/traccar/geofence/GeofencePolyline.java23
-rw-r--r--src/main/java/org/traccar/geolocation/GoogleGeolocationProvider.java8
-rw-r--r--src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java8
-rw-r--r--src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java16
-rw-r--r--src/main/java/org/traccar/geolocation/UniversalGeolocationProvider.java18
-rw-r--r--src/main/java/org/traccar/geolocation/UnwiredGeolocationProvider.java22
-rw-r--r--src/main/java/org/traccar/handler/AcknowledgementHandler.java121
-rw-r--r--src/main/java/org/traccar/handler/ComputedAttributesHandler.java114
-rw-r--r--src/main/java/org/traccar/handler/CopyAttributesHandler.java36
-rw-r--r--src/main/java/org/traccar/handler/DefaultDataHandler.java19
-rw-r--r--src/main/java/org/traccar/handler/DistanceHandler.java20
-rw-r--r--src/main/java/org/traccar/handler/EngineHoursHandler.java19
-rw-r--r--src/main/java/org/traccar/handler/FilterHandler.java158
-rw-r--r--src/main/java/org/traccar/handler/GeocoderHandler.java22
-rw-r--r--src/main/java/org/traccar/handler/GeofenceHandler.java52
-rw-r--r--src/main/java/org/traccar/handler/GeolocationHandler.java45
-rw-r--r--src/main/java/org/traccar/handler/HemisphereHandler.java9
-rw-r--r--src/main/java/org/traccar/handler/MotionHandler.java22
-rw-r--r--src/main/java/org/traccar/handler/NetworkForwarderHandler.java72
-rw-r--r--src/main/java/org/traccar/handler/RemoteAddressHandler.java26
-rw-r--r--src/main/java/org/traccar/handler/SpeedLimitHandler.java7
-rw-r--r--src/main/java/org/traccar/handler/StandardLoggingHandler.java8
-rw-r--r--src/main/java/org/traccar/handler/TimeHandler.java19
-rw-r--r--src/main/java/org/traccar/handler/events/AlertEventHandler.java17
-rw-r--r--src/main/java/org/traccar/handler/events/BaseEventHandler.java17
-rw-r--r--src/main/java/org/traccar/handler/events/BehaviorEventHandler.java16
-rw-r--r--src/main/java/org/traccar/handler/events/CommandResultEventHandler.java10
-rw-r--r--src/main/java/org/traccar/handler/events/DriverEventHandler.java25
-rw-r--r--src/main/java/org/traccar/handler/events/FuelDropEventHandler.java70
-rw-r--r--src/main/java/org/traccar/handler/events/FuelEventHandler.java79
-rw-r--r--src/main/java/org/traccar/handler/events/GeofenceEventHandler.java80
-rw-r--r--src/main/java/org/traccar/handler/events/IgnitionEventHandler.java26
-rw-r--r--src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java44
-rw-r--r--src/main/java/org/traccar/handler/events/MediaEventHandler.java49
-rw-r--r--src/main/java/org/traccar/handler/events/MotionEventHandler.java139
-rw-r--r--src/main/java/org/traccar/handler/events/OverspeedEventHandler.java139
-rw-r--r--src/main/java/org/traccar/helper/BitUtil.java4
-rw-r--r--src/main/java/org/traccar/helper/BufferUtil.java48
-rw-r--r--src/main/java/org/traccar/helper/Checksum.java15
-rw-r--r--src/main/java/org/traccar/helper/ClassScanner.java2
-rw-r--r--src/main/java/org/traccar/helper/Log.java36
-rw-r--r--src/main/java/org/traccar/helper/LogAction.java17
-rw-r--r--src/main/java/org/traccar/helper/NetworkUtil.java31
-rw-r--r--src/main/java/org/traccar/helper/ObdDecoder.java36
-rw-r--r--src/main/java/org/traccar/helper/ObjectMapperContextResolver.java38
-rw-r--r--src/main/java/org/traccar/helper/Parser.java29
-rw-r--r--src/main/java/org/traccar/helper/PatternUtil.java2
-rw-r--r--src/main/java/org/traccar/helper/StringUtil.java32
-rw-r--r--src/main/java/org/traccar/helper/WebHelper.java (renamed from src/main/java/org/traccar/helper/ServletHelper.java)26
-rw-r--r--src/main/java/org/traccar/helper/model/AttributeUtil.java188
-rw-r--r--src/main/java/org/traccar/helper/model/DeviceUtil.java79
-rw-r--r--src/main/java/org/traccar/helper/model/GeofenceUtil.java42
-rw-r--r--src/main/java/org/traccar/helper/model/PositionUtil.java80
-rw-r--r--src/main/java/org/traccar/helper/model/UserUtil.java78
-rw-r--r--src/main/java/org/traccar/mail/LogMailManager.java48
-rw-r--r--src/main/java/org/traccar/mail/MailManager.java33
-rw-r--r--src/main/java/org/traccar/mail/SmtpMailManager.java162
-rw-r--r--src/main/java/org/traccar/model/BaseCommand.java (renamed from src/main/java/org/traccar/database/CalendarManager.java)17
-rw-r--r--src/main/java/org/traccar/model/BaseModel.java6
-rw-r--r--src/main/java/org/traccar/model/Calendar.java31
-rw-r--r--src/main/java/org/traccar/model/CellTower.java38
-rw-r--r--src/main/java/org/traccar/model/Command.java22
-rw-r--r--src/main/java/org/traccar/model/Device.java150
-rw-r--r--src/main/java/org/traccar/model/DeviceState.java71
-rw-r--r--src/main/java/org/traccar/model/Disableable.java39
-rw-r--r--src/main/java/org/traccar/model/Driver.java2
-rw-r--r--src/main/java/org/traccar/model/Event.java4
-rw-r--r--src/main/java/org/traccar/model/ExtendedModel.java48
-rw-r--r--src/main/java/org/traccar/model/Geofence.java34
-rw-r--r--src/main/java/org/traccar/model/Network.java26
-rw-r--r--src/main/java/org/traccar/model/Notification.java26
-rw-r--r--src/main/java/org/traccar/model/Permission.java26
-rw-r--r--src/main/java/org/traccar/model/Position.java30
-rw-r--r--src/main/java/org/traccar/model/QueuedCommand.java46
-rw-r--r--src/main/java/org/traccar/model/Report.java55
-rw-r--r--src/main/java/org/traccar/model/Schedulable.java (renamed from src/main/java/org/traccar/model/ScheduledModel.java)16
-rw-r--r--src/main/java/org/traccar/model/Server.java111
-rw-r--r--src/main/java/org/traccar/model/User.java61
-rw-r--r--src/main/java/org/traccar/model/UserRestrictions.java24
-rw-r--r--src/main/java/org/traccar/model/WifiAccessPoint.java23
-rw-r--r--src/main/java/org/traccar/notification/EventForwarder.java106
-rw-r--r--src/main/java/org/traccar/notification/NotificationFormatter.java51
-rw-r--r--src/main/java/org/traccar/notification/NotificatorManager.java106
-rw-r--r--src/main/java/org/traccar/notification/PropertiesProvider.java28
-rw-r--r--src/main/java/org/traccar/notification/TextTemplateFormatter.java43
-rw-r--r--src/main/java/org/traccar/notificators/Notificator.java23
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorCommand.java62
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorFirebase.java169
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorMail.java29
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorNull.java38
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorPushover.java75
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorSms.java42
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorTelegram.java66
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorTraccar.java124
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorWeb.java40
-rw-r--r--src/main/java/org/traccar/protocol/AdmProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/AdmProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/AisProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/AisProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/AlematicsProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/AlematicsProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/AnytrekProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/AnytrekProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/ApelProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/ApelProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/AplicomProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/AplicomProtocolDecoder.java5
-rw-r--r--src/main/java/org/traccar/protocol/AppelloProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/AppelloProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/AquilaProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/AquilaProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Ardi01Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Ardi01ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/ArknavProtocol.java21
-rw-r--r--src/main/java/org/traccar/protocol/ArknavProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/ArknavX8Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/ArknavX8ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/ArmoliProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/ArmoliProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/ArnaviProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java10
-rw-r--r--src/main/java/org/traccar/protocol/ArnaviTextProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/AstraProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/AstraProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/At2000Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/At2000ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/AtrackProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java242
-rw-r--r--src/main/java/org/traccar/protocol/AuroProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/AuroProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/AustinNbProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/AustinNbProtocolDecoder.java7
-rw-r--r--src/main/java/org/traccar/protocol/AutoFonProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/AutoFonProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/AutoGradeProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/AutoGradeProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/AutoTrackProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/AutoTrackProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/AvemaProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/AvemaProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Avl301Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Avl301ProtocolDecoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/B2316Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/B2316ProtocolDecoder.java11
-rw-r--r--src/main/java/org/traccar/protocol/BceProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/BceProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/BlackKiteProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/BlackKiteProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/BlueProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/BlueProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/BoxProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/BoxProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/BstplProtocol.java43
-rw-r--r--src/main/java/org/traccar/protocol/BstplProtocolDecoder.java137
-rw-r--r--src/main/java/org/traccar/protocol/C2stekProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/C2stekProtocolDecoder.java14
-rw-r--r--src/main/java/org/traccar/protocol/CalAmpProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/CalAmpProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/CarTrackProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/CarTrackProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/CarcellProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/CarcellProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/CarscopProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/CarscopProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/CastelProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/CastelProtocolDecoder.java41
-rw-r--r--src/main/java/org/traccar/protocol/CastelProtocolEncoder.java7
-rw-r--r--src/main/java/org/traccar/protocol/CautelaProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/CautelaProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/CellocatorProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java12
-rw-r--r--src/main/java/org/traccar/protocol/CguardProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/CguardProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/CityeasyProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/CityeasyProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/ContinentalProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/ContinentalProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/CradlepointProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/CradlepointProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/DingtekProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/DingtekProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/DishaProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/DishaProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/DmtHttpProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java8
-rw-r--r--src/main/java/org/traccar/protocol/DmtProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/DmtProtocolDecoder.java6
-rw-r--r--src/main/java/org/traccar/protocol/DolphinProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/DolphinProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Dsf22Protocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/Dsf22ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/DualcamProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java41
-rw-r--r--src/main/java/org/traccar/protocol/DwayProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/DwayProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/EasyTrackProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/EelinkProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java15
-rw-r--r--src/main/java/org/traccar/protocol/EgtsProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/EgtsProtocolDecoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/EnforaProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/EnforaProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/EnnfuProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/EnnfuProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/EnvotechProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/EnvotechProtocolDecoder.java29
-rw-r--r--src/main/java/org/traccar/protocol/EsealProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/EsealProtocolDecoder.java11
-rw-r--r--src/main/java/org/traccar/protocol/EskyProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/EskyProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/ExtremTracProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/ExtremTracProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/FifotrackProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java46
-rw-r--r--src/main/java/org/traccar/protocol/FlespiProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java45
-rw-r--r--src/main/java/org/traccar/protocol/FlexApiProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java6
-rw-r--r--src/main/java/org/traccar/protocol/FlexCommProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/FlexCommProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/FlexibleReportProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/FlexibleReportProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/FlextrackProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/FlextrackProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/FoxProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/FoxProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/FreedomProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/FreedomProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/FreematicsProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/FutureWayProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/FutureWayProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/G1rusFrameDecoder.java49
-rw-r--r--src/main/java/org/traccar/protocol/G1rusProtocol.java40
-rw-r--r--src/main/java/org/traccar/protocol/G1rusProtocolDecoder.java165
-rw-r--r--src/main/java/org/traccar/protocol/GalileoFrameDecoder.java16
-rw-r--r--src/main/java/org/traccar/protocol/GalileoProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/GalileoProtocolDecoder.java168
-rw-r--r--src/main/java/org/traccar/protocol/GatorProtocol.java17
-rw-r--r--src/main/java/org/traccar/protocol/GatorProtocolDecoder.java3
-rw-r--r--src/main/java/org/traccar/protocol/GatorProtocolEncoder.java76
-rw-r--r--src/main/java/org/traccar/protocol/GenxProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/GenxProtocolDecoder.java9
-rw-r--r--src/main/java/org/traccar/protocol/Gl100Protocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/Gl100ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Gl200BinaryProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Gl200Protocol.java15
-rw-r--r--src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java10
-rw-r--r--src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java906
-rw-r--r--src/main/java/org/traccar/protocol/GlobalSatProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/GlobalSatProtocolDecoder.java10
-rw-r--r--src/main/java/org/traccar/protocol/GlobalstarProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java14
-rw-r--r--src/main/java/org/traccar/protocol/GnxProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/GnxProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/GoSafeProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java14
-rw-r--r--src/main/java/org/traccar/protocol/GotopProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/GotopProtocolDecoder.java21
-rw-r--r--src/main/java/org/traccar/protocol/Gps056Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Gps056ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Gps103Protocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java25
-rw-r--r--src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/GpsGateProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/GpsGateProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/GpsMarkerProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/GpsMarkerProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/GpsmtaProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/GpsmtaProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/GranitProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/GranitProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Gs100Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Gs100ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Gt02Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Gt02ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Gt06Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java1062
-rw-r--r--src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java42
-rw-r--r--src/main/java/org/traccar/protocol/Gt30Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Gt30ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/H02Protocol.java17
-rw-r--r--src/main/java/org/traccar/protocol/H02ProtocolDecoder.java8
-rw-r--r--src/main/java/org/traccar/protocol/H02ProtocolEncoder.java10
-rw-r--r--src/main/java/org/traccar/protocol/HaicomProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/HaicomProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/HomtecsProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/HomtecsProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/HoopoProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/HoopoProtocolDecoder.java6
-rw-r--r--src/main/java/org/traccar/protocol/HuaShengProtocol.java20
-rw-r--r--src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java24
-rw-r--r--src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java85
-rw-r--r--src/main/java/org/traccar/protocol/HuabaoProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java493
-rw-r--r--src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java9
-rw-r--r--src/main/java/org/traccar/protocol/HunterProProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/HunterProProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/IdplProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/IdplProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/IntellitracProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/IntellitracProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/IotmProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/IotmProtocolDecoder.java8
-rw-r--r--src/main/java/org/traccar/protocol/ItsProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/ItsProtocolDecoder.java5
-rw-r--r--src/main/java/org/traccar/protocol/Ivt401Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Ivt401ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/JidoProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/JidoProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/JpKorjarProtocol.java12
-rw-r--r--src/main/java/org/traccar/protocol/JpKorjarProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Jt600FrameDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Jt600Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java21
-rw-r--r--src/main/java/org/traccar/protocol/KenjiProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/KenjiProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/KhdProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/KhdProtocolDecoder.java5
-rw-r--r--src/main/java/org/traccar/protocol/KhdProtocolEncoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/L100Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/L100ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/LacakProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/LacakProtocolDecoder.java6
-rw-r--r--src/main/java/org/traccar/protocol/LaipacProtocol.java12
-rw-r--r--src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java42
-rw-r--r--src/main/java/org/traccar/protocol/LeafSpyProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/M2cProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/M2cProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/M2mProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/M2mProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/MaestroProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/MaestroProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/ManPowerProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/ManPowerProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Mavlink2Protocol.java11
-rw-r--r--src/main/java/org/traccar/protocol/Mavlink2ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/MegastekProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/MegastekProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/MeiligaoProtocol.java15
-rw-r--r--src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java10
-rw-r--r--src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java54
-rw-r--r--src/main/java/org/traccar/protocol/MeitrackProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java115
-rw-r--r--src/main/java/org/traccar/protocol/MeitrackProtocolEncoder.java9
-rw-r--r--src/main/java/org/traccar/protocol/MictrackProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/MilesmateProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/MilesmateProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/MiniFinderProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java18
-rw-r--r--src/main/java/org/traccar/protocol/Minifinder2Protocol.java18
-rw-r--r--src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java72
-rw-r--r--src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java67
-rw-r--r--src/main/java/org/traccar/protocol/MobilogixProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/MobilogixProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/MoovboxProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/MoovboxProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/MotorProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/MotorProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Mta6Protocol.java13
-rw-r--r--src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/MtxProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/MtxProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/MxtProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/MxtProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/NavigilProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/NavigilProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/NavisProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/NavisProtocolDecoder.java11
-rw-r--r--src/main/java/org/traccar/protocol/NavisetProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/NavisetProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/NavtelecomProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java22
-rw-r--r--src/main/java/org/traccar/protocol/NdtpV6Protocol.java39
-rw-r--r--src/main/java/org/traccar/protocol/NdtpV6ProtocolDecoder.java203
-rw-r--r--src/main/java/org/traccar/protocol/NdtpV6ProtocolEncoder.java42
-rw-r--r--src/main/java/org/traccar/protocol/NeosProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/NeosProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/NetProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/NetProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/NiotProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/NiotProtocolDecoder.java13
-rw-r--r--src/main/java/org/traccar/protocol/NoranProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/NoranProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/NvsProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/NvsProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/NyitechProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/NyitechProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/ObdDongleProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/ObdDongleProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/OigoProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/OigoProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/OkoProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/OkoProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/OmnicommProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/OmnicommProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/OpenGtsProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/OpenGtsProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/OrbcommProtocol.java12
-rw-r--r--src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java13
-rw-r--r--src/main/java/org/traccar/protocol/OrbcommProtocolPoller.java12
-rw-r--r--src/main/java/org/traccar/protocol/OrionProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/OrionProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/OsmAndProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java31
-rw-r--r--src/main/java/org/traccar/protocol/OutsafeProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java12
-rw-r--r--src/main/java/org/traccar/protocol/OwnTracksProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java6
-rw-r--r--src/main/java/org/traccar/protocol/PacificTrackProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/PacificTrackProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/PathAwayProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/PathAwayProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/PiligrimProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java58
-rw-r--r--src/main/java/org/traccar/protocol/PluginProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/PluginProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/PolteProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/PolteProtocolDecoder.java6
-rw-r--r--src/main/java/org/traccar/protocol/PortmanProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/PortmanProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/PretraceProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/PretraceProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/PretraceProtocolEncoder.java5
-rw-r--r--src/main/java/org/traccar/protocol/PricolProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/PricolProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/ProgressProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/ProgressProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/PstProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/PstProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Pt215Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Pt215ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Pt3000Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Pt3000ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Pt502Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java6
-rw-r--r--src/main/java/org/traccar/protocol/Pt60Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Pt60ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/R12wProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/R12wProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/RaceDynamicsProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/RadarProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/RadarProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/RaveonProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/RaveonProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/RecodaProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/RecodaProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/RetranslatorProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/RetranslatorProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/RfTrackProtocol.java43
-rw-r--r--src/main/java/org/traccar/protocol/RfTrackProtocolDecoder.java163
-rw-r--r--src/main/java/org/traccar/protocol/RitiProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/RitiProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/RoboTrackProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/RoboTrackProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/RstProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/RstProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/RuptelaProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java146
-rw-r--r--src/main/java/org/traccar/protocol/RuptelaProtocolEncoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/S168Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/S168ProtocolDecoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/SabertekProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/SabertekProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/SanavProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/SanavProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/SanulProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/SanulProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/SatsolProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/SatsolProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/SigfoxProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java27
-rw-r--r--src/main/java/org/traccar/protocol/SiwiProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/SiwiProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/SkypatrolProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/SkypatrolProtocolDecoder.java11
-rw-r--r--src/main/java/org/traccar/protocol/SmartSoleProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/SmartSoleProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/SmokeyProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/SmokeyProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/SolarPoweredProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/SpotProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/SpotProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/StarLinkProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java28
-rw-r--r--src/main/java/org/traccar/protocol/StarcomProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/StartekProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/StartekProtocolDecoder.java54
-rw-r--r--src/main/java/org/traccar/protocol/StbProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/StbProtocolDecoder.java39
-rw-r--r--src/main/java/org/traccar/protocol/Stl060Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Stl060ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/SuntechProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java95
-rw-r--r--src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java28
-rw-r--r--src/main/java/org/traccar/protocol/SupermateProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/SupermateProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/SviasProtocol.java11
-rw-r--r--src/main/java/org/traccar/protocol/SviasProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/SwiftechProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/SwiftechProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/T55Protocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/T55ProtocolDecoder.java122
-rw-r--r--src/main/java/org/traccar/protocol/T57Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/T57ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/T622IridiumProtocol.java39
-rw-r--r--src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java149
-rw-r--r--src/main/java/org/traccar/protocol/T800xProtocol.java19
-rw-r--r--src/main/java/org/traccar/protocol/T800xProtocolDecoder.java15
-rw-r--r--src/main/java/org/traccar/protocol/TaipPrefixEncoder.java15
-rw-r--r--src/main/java/org/traccar/protocol/TaipProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/TaipProtocolDecoder.java5
-rw-r--r--src/main/java/org/traccar/protocol/TechTltProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TechTltProtocolDecoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/TechtoCruzProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TechtoCruzProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/TekProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TekProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/TelemaxProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TelemaxProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/TelicProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TelicProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/TeltonikaProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java386
-rw-r--r--src/main/java/org/traccar/protocol/TeraTrackProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java8
-rw-r--r--src/main/java/org/traccar/protocol/ThinkPowerProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/ThinkPowerProtocolDecoder.java9
-rw-r--r--src/main/java/org/traccar/protocol/ThinkRaceProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/ThinkRaceProtocolDecoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/ThurayaProtocol.java39
-rw-r--r--src/main/java/org/traccar/protocol/ThurayaProtocolDecoder.java195
-rw-r--r--src/main/java/org/traccar/protocol/Tk102Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Tk102ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Tk103Protocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java165
-rw-r--r--src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java11
-rw-r--r--src/main/java/org/traccar/protocol/Tlt2hProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java31
-rw-r--r--src/main/java/org/traccar/protocol/TlvProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TlvProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/TmgProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TmgProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/TopflytechProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TopflytechProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/TopinProtocol.java19
-rw-r--r--src/main/java/org/traccar/protocol/TopinProtocolDecoder.java9
-rw-r--r--src/main/java/org/traccar/protocol/TotemProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TotemProtocolDecoder.java197
-rw-r--r--src/main/java/org/traccar/protocol/Tr20Protocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/Tr20ProtocolDecoder.java6
-rw-r--r--src/main/java/org/traccar/protocol/Tr900Protocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/Tr900ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/TrackboxProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TrackboxProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/TrakMateProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TrakMateProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/TramigoFrameDecoder.java8
-rw-r--r--src/main/java/org/traccar/protocol/TramigoProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java266
-rw-r--r--src/main/java/org/traccar/protocol/TranSyncProtocol.java39
-rw-r--r--src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java166
-rw-r--r--src/main/java/org/traccar/protocol/TrvProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TrvProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Tt8850Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Tt8850ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/TytanProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TytanProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/TzoneProtocol.java11
-rw-r--r--src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java44
-rw-r--r--src/main/java/org/traccar/protocol/UlbotechProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/UlbotechProtocolDecoder.java10
-rw-r--r--src/main/java/org/traccar/protocol/UproProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/UproProtocolDecoder.java5
-rw-r--r--src/main/java/org/traccar/protocol/UuxProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/UuxProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/V680Protocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/V680ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/VisiontekProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/VisiontekProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/VltProtocol.java43
-rw-r--r--src/main/java/org/traccar/protocol/VltProtocolDecoder.java139
-rw-r--r--src/main/java/org/traccar/protocol/VnetProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/VnetProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Vt200Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java4
-rw-r--r--src/main/java/org/traccar/protocol/VtfmsProtocol.java15
-rw-r--r--src/main/java/org/traccar/protocol/VtfmsProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/WatchFrameDecoder.java23
-rw-r--r--src/main/java/org/traccar/protocol/WatchProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/WatchProtocolDecoder.java117
-rw-r--r--src/main/java/org/traccar/protocol/WatchProtocolEncoder.java3
-rw-r--r--src/main/java/org/traccar/protocol/WialonProtocol.java26
-rw-r--r--src/main/java/org/traccar/protocol/WialonProtocolDecoder.java25
-rw-r--r--src/main/java/org/traccar/protocol/WliProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/WliProtocolDecoder.java76
-rw-r--r--src/main/java/org/traccar/protocol/WondexProtocol.java15
-rw-r--r--src/main/java/org/traccar/protocol/WondexProtocolDecoder.java11
-rw-r--r--src/main/java/org/traccar/protocol/WristbandProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/WristbandProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Xexun2FrameEncoder.java48
-rw-r--r--src/main/java/org/traccar/protocol/Xexun2Protocol.java18
-rw-r--r--src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java50
-rw-r--r--src/main/java/org/traccar/protocol/Xexun2ProtocolEncoder.java70
-rw-r--r--src/main/java/org/traccar/protocol/XexunProtocol.java18
-rw-r--r--src/main/java/org/traccar/protocol/XexunProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/XirgoProtocol.java17
-rw-r--r--src/main/java/org/traccar/protocol/XirgoProtocolDecoder.java9
-rw-r--r--src/main/java/org/traccar/protocol/Xrb28Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Xt013Protocol.java15
-rw-r--r--src/main/java/org/traccar/protocol/Xt013ProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/Xt2400Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java8
-rw-r--r--src/main/java/org/traccar/protocol/YwtProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/YwtProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/reports/CombinedReportProvider.java83
-rw-r--r--src/main/java/org/traccar/reports/CsvExportProvider.java76
-rw-r--r--src/main/java/org/traccar/reports/Events.java133
-rw-r--r--src/main/java/org/traccar/reports/EventsReportProvider.java170
-rw-r--r--src/main/java/org/traccar/reports/GpxExportProvider.java76
-rw-r--r--src/main/java/org/traccar/reports/KmlExportProvider.java80
-rw-r--r--src/main/java/org/traccar/reports/ReportUtils.java368
-rw-r--r--src/main/java/org/traccar/reports/Route.java85
-rw-r--r--src/main/java/org/traccar/reports/RouteReportProvider.java113
-rw-r--r--src/main/java/org/traccar/reports/Stops.java102
-rw-r--r--src/main/java/org/traccar/reports/StopsReportProvider.java104
-rw-r--r--src/main/java/org/traccar/reports/Summary.java151
-rw-r--r--src/main/java/org/traccar/reports/SummaryReportProvider.java192
-rw-r--r--src/main/java/org/traccar/reports/Trips.java100
-rw-r--r--src/main/java/org/traccar/reports/TripsReportProvider.java104
-rw-r--r--src/main/java/org/traccar/reports/common/ExpressionEvaluatorFactory.java58
-rw-r--r--src/main/java/org/traccar/reports/common/ReportExecutor.java25
-rw-r--r--src/main/java/org/traccar/reports/common/ReportMailer.java65
-rw-r--r--src/main/java/org/traccar/reports/common/ReportUtils.java406
-rw-r--r--src/main/java/org/traccar/reports/common/TripsConfig.java73
-rw-r--r--src/main/java/org/traccar/reports/model/BaseReportItem.java (renamed from src/main/java/org/traccar/reports/model/BaseReport.java)2
-rw-r--r--src/main/java/org/traccar/reports/model/CombinedReportItem.java65
-rw-r--r--src/main/java/org/traccar/reports/model/DeviceReportSection.java (renamed from src/main/java/org/traccar/reports/model/DeviceReport.java)2
-rw-r--r--src/main/java/org/traccar/reports/model/StopReportItem.java (renamed from src/main/java/org/traccar/reports/model/StopReport.java)2
-rw-r--r--src/main/java/org/traccar/reports/model/SummaryReportItem.java (renamed from src/main/java/org/traccar/reports/model/SummaryReport.java)2
-rw-r--r--src/main/java/org/traccar/reports/model/TripReportItem.java (renamed from src/main/java/org/traccar/reports/model/TripReport.java)2
-rw-r--r--src/main/java/org/traccar/reports/model/TripsConfig.java105
-rw-r--r--src/main/java/org/traccar/schedule/ScheduleManager.java23
-rw-r--r--src/main/java/org/traccar/schedule/ScheduleTask.java (renamed from src/main/java/org/traccar/database/OrderManager.java)14
-rw-r--r--src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java73
-rw-r--r--src/main/java/org/traccar/schedule/TaskHealthCheck.java23
-rw-r--r--src/main/java/org/traccar/schedule/TaskReports.java146
-rw-r--r--src/main/java/org/traccar/schedule/TaskWebSocketKeepalive.java17
-rw-r--r--src/main/java/org/traccar/session/ConnectionManager.java376
-rw-r--r--src/main/java/org/traccar/session/DeviceSession.java (renamed from src/main/java/org/traccar/database/ActiveDevice.java)50
-rw-r--r--src/main/java/org/traccar/session/Endpoint.java58
-rw-r--r--src/main/java/org/traccar/session/cache/CacheKey.java57
-rw-r--r--src/main/java/org/traccar/session/cache/CacheManager.java428
-rw-r--r--src/main/java/org/traccar/session/cache/CacheValue.java53
-rw-r--r--src/main/java/org/traccar/session/state/MotionProcessor.java81
-rw-r--r--src/main/java/org/traccar/session/state/MotionState.java101
-rw-r--r--src/main/java/org/traccar/session/state/OverspeedProcessor.java71
-rw-r--r--src/main/java/org/traccar/session/state/OverspeedState.java88
-rw-r--r--src/main/java/org/traccar/sms/HttpSmsClient.java70
-rw-r--r--src/main/java/org/traccar/sms/SmsManager.java8
-rw-r--r--src/main/java/org/traccar/sms/SnsSmsClient.java33
-rw-r--r--src/main/java/org/traccar/speedlimit/OverpassSpeedLimitProvider.java18
-rw-r--r--src/main/java/org/traccar/storage/DatabaseModule.java103
-rw-r--r--src/main/java/org/traccar/storage/DatabaseStorage.java243
-rw-r--r--src/main/java/org/traccar/storage/MemoryStorage.java146
-rw-r--r--src/main/java/org/traccar/storage/QueryBuilder.java96
-rw-r--r--src/main/java/org/traccar/storage/QueryExtended.java27
-rw-r--r--src/main/java/org/traccar/storage/Storage.java25
-rw-r--r--src/main/java/org/traccar/storage/StorageException.java15
-rw-r--r--src/main/java/org/traccar/storage/StorageName.java15
-rw-r--r--src/main/java/org/traccar/storage/query/Columns.java20
-rw-r--r--src/main/java/org/traccar/storage/query/Condition.java104
-rw-r--r--src/main/java/org/traccar/storage/query/Limit.java15
-rw-r--r--src/main/java/org/traccar/storage/query/Order.java25
-rw-r--r--src/main/java/org/traccar/storage/query/Request.java27
-rw-r--r--src/main/java/org/traccar/web/ConsoleServlet.java22
-rw-r--r--src/main/java/org/traccar/web/ModernDefaultServlet.java59
-rw-r--r--src/main/java/org/traccar/web/OverrideFilter.java87
-rw-r--r--src/main/java/org/traccar/web/ResponseWrapper.java83
-rw-r--r--src/main/java/org/traccar/web/ThrottlingFilter.java54
-rw-r--r--src/main/java/org/traccar/web/WebInjectionManagerFactory.java50
-rw-r--r--src/main/java/org/traccar/web/WebModule.java31
-rw-r--r--src/main/java/org/traccar/web/WebServer.java129
-rw-r--r--src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory1
-rw-r--r--src/main/resources/META-INF/services/org.jxls.expression.ExpressionEvaluatorFactory1
-rw-r--r--src/test/java/org/traccar/BaseTest.java77
-rw-r--r--src/test/java/org/traccar/ProtocolTest.java96
-rw-r--r--src/test/java/org/traccar/TestIdentityManager.java80
-rw-r--r--src/test/java/org/traccar/WebDataHandlerTest.java28
-rw-r--r--src/test/java/org/traccar/calendar/CalendarTest.java26
-rw-r--r--src/test/java/org/traccar/config/ConfigTest.java6
-rw-r--r--src/test/java/org/traccar/database/GroupTreeTest.java4
-rw-r--r--src/test/java/org/traccar/forward/PositionForwarderUrlTest.java42
-rw-r--r--src/test/java/org/traccar/geocoder/AddressFormatTest.java4
-rw-r--r--src/test/java/org/traccar/geocoder/GeocoderTest.java64
-rw-r--r--src/test/java/org/traccar/geofence/GeofenceCircleTest.java21
-rw-r--r--src/test/java/org/traccar/geofence/GeofencePolygonTest.java47
-rw-r--r--src/test/java/org/traccar/geofence/GeofencePolylineTest.java54
-rw-r--r--src/test/java/org/traccar/geolocation/GeolocationProviderTest.java23
-rw-r--r--src/test/java/org/traccar/handler/ComputedAttributesTest.java12
-rw-r--r--src/test/java/org/traccar/handler/DistanceHandlerTest.java8
-rw-r--r--src/test/java/org/traccar/handler/FilterHandlerTest.java100
-rw-r--r--src/test/java/org/traccar/handler/MotionHandlerTest.java22
-rw-r--r--src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java18
-rw-r--r--src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java12
-rw-r--r--src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java15
-rw-r--r--src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java60
-rw-r--r--src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java175
-rw-r--r--src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java140
-rw-r--r--src/test/java/org/traccar/helper/BcdUtilTest.java4
-rw-r--r--src/test/java/org/traccar/helper/BitBufferTest.java4
-rw-r--r--src/test/java/org/traccar/helper/BitUtilTest.java8
-rw-r--r--src/test/java/org/traccar/helper/BufferUtilTest.java10
-rw-r--r--src/test/java/org/traccar/helper/ChecksumTest.java4
-rw-r--r--src/test/java/org/traccar/helper/DateBuilderTest.java4
-rw-r--r--src/test/java/org/traccar/helper/DateUtilTest.java4
-rw-r--r--src/test/java/org/traccar/helper/DistanceCalculatorTest.java4
-rw-r--r--src/test/java/org/traccar/helper/LogTest.java4
-rw-r--r--src/test/java/org/traccar/helper/ObdDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/helper/PatternBuilderTest.java4
-rw-r--r--src/test/java/org/traccar/helper/PatternUtilTest.java8
-rw-r--r--src/test/java/org/traccar/helper/ServletHelperTest.java65
-rw-r--r--src/test/java/org/traccar/helper/WebHelperTest.java39
-rw-r--r--src/test/java/org/traccar/notification/NotificiationMailTest.java18
-rw-r--r--src/test/java/org/traccar/protocol/AdmFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ArmoliProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java10
-rw-r--r--src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java14
-rw-r--r--src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java12
-rw-r--r--src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/B2316ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/BceFrameDecoderTest.java26
-rw-r--r--src/test/java/org/traccar/protocol/BceProtocolDecoderTest.java17
-rw-r--r--src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/BstplProtocolDecoderTest.java21
-rw-r--r--src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java7
-rw-r--r--src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java12
-rw-r--r--src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java9
-rw-r--r--src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/DingtekFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/DingtekProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/DolphinProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Dsf22FrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Dsf22ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/DualcamFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/EasyTrackProtocolEncoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java21
-rw-r--r--src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/EnnfuProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java13
-rw-r--r--src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/FifotrackFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java11
-rw-r--r--src/test/java/org/traccar/protocol/FifotrackProtocolEncoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/FlexApiProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/FlexibleReportProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java7
-rw-r--r--src/test/java/org/traccar/protocol/FutureWayFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/FutureWayProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/G1rusProtocolDecoderTest.java18
-rw-r--r--src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java10
-rw-r--r--src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java24
-rw-r--r--src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java23
-rw-r--r--src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java44
-rw-r--r--src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/GlobalSatProtocolEncoderTest.java12
-rw-r--r--src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java7
-rw-r--r--src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java18
-rw-r--r--src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java10
-rw-r--r--src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Gs100ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java87
-rw-r--r--src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/H02FrameDecoderTest.java10
-rw-r--r--src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java9
-rw-r--r--src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java14
-rw-r--r--src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/HoopoProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java14
-rw-r--r--src/test/java/org/traccar/protocol/HuaShengProtocolEncoderTest.java33
-rw-r--r--src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java70
-rw-r--r--src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/IotmProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ItsFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ItsProtocolEncoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/JidoProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/JsonFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java12
-rw-r--r--src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java6
-rwxr-xr-xsrc/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java9
-rw-r--r--src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/L100FrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/LacakProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/LeafSpyProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Mavlink2ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/MegastekProtocolDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java36
-rw-r--r--src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/MictrackProtocolDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java24
-rw-r--r--src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java29
-rw-r--r--src/test/java/org/traccar/protocol/MobilogixProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/MoovboxProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/MotorProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java3
-rw-r--r--src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java9
-rw-r--r--src/test/java/org/traccar/protocol/NavisetFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/NavisetProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java10
-rw-r--r--src/test/java/org/traccar/protocol/NavtelecomProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/NdtpV6ProtocolDecoderTest.java18
-rw-r--r--src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/NetProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/NiotProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/OmnicommProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/PacificTrackProtocolDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/PolteProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/PortmanProtocolEncoderTest.java12
-rw-r--r--src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/PstFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/PstFrameEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/PstProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/PstProtocolEncoderTest.java10
-rw-r--r--src/test/java/org/traccar/protocol/Pt215ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java12
-rw-r--r--src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/R12wProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/RadarProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/RfTrackProtocolDecoderTest.java19
-rw-r--r--src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java10
-rw-r--r--src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/S168ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/SanulProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java17
-rw-r--r--src/test/java/org/traccar/protocol/StartekProtocolEncoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/StbProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java165
-rwxr-xr-xsrc/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/SwiftechProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java12
-rw-r--r--src/test/java/org/traccar/protocol/T57FrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java21
-rw-r--r--src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java10
-rw-r--r--src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TechTltProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TechtoCruzFrameDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/TechtoCruzProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TekFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TeltonikaFrameDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java32
-rw-r--r--src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TeraTrackProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ThinkPowerProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/ThurayaProtocolDecoderTest.java24
-rw-r--r--src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java17
-rw-r--r--src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java86
-rw-r--r--src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java11
-rw-r--r--src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java7
-rw-r--r--src/test/java/org/traccar/protocol/TopinProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java12
-rw-r--r--src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java7
-rw-r--r--src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java10
-rw-r--r--src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java21
-rw-r--r--src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java12
-rw-r--r--src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/UlbotechProtocolEncoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/UuxProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/VltProtocolDecoderTest.java22
-rw-r--r--src/test/java/org/traccar/protocol/VnetProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java12
-rw-r--r--src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java57
-rw-r--r--src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java11
-rw-r--r--src/test/java/org/traccar/protocol/WliFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/WliProtocolDecoderTest.java7
-rw-r--r--src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/Xexun2FrameEncoderTest.java21
-rw-r--r--src/test/java/org/traccar/protocol/Xexun2ProtocolDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/Xexun2ProtocolEncoderTest.java29
-rw-r--r--src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java13
-rw-r--r--src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java12
-rw-r--r--src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/reports/ReportUtilsTest.java235
-rw-r--r--src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java23
-rw-r--r--src/test/java/org/traccar/web/WebServerTest.java2
-rw-r--r--swagger.json150
-rw-r--r--templates/export/events.xlsxbin8763 -> 9023 bytes
-rw-r--r--templates/full/alarm.vm84
-rw-r--r--templates/full/commandResult.vm6
-rw-r--r--templates/full/deviceFuelDrop.vm4
-rw-r--r--templates/full/deviceFuelIncrease.vm11
-rw-r--r--templates/full/deviceInactive.vm6
-rw-r--r--templates/full/deviceMoving.vm4
-rw-r--r--templates/full/deviceOffline.vm5
-rw-r--r--templates/full/deviceOnline.vm5
-rw-r--r--templates/full/deviceOverspeed.vm4
-rw-r--r--templates/full/deviceStopped.vm4
-rw-r--r--templates/full/deviceUnknown.vm5
-rw-r--r--templates/full/driverChanged.vm6
-rw-r--r--templates/full/geofenceEnter.vm4
-rw-r--r--templates/full/geofenceExit.vm4
-rw-r--r--templates/full/ignitionOff.vm4
-rw-r--r--templates/full/ignitionOn.vm4
-rw-r--r--templates/full/maintenance.vm4
-rw-r--r--templates/full/media.vm13
-rw-r--r--templates/full/passwordReset.vm2
-rw-r--r--templates/full/test.vm2
-rw-r--r--templates/full/textMessage.vm6
-rw-r--r--templates/short/alarm.vm80
-rw-r--r--templates/short/deviceFuelIncrease.vm2
-rw-r--r--templates/short/media.vm2
-rwxr-xr-x[-rw-r--r--]tools/config-doc.py (renamed from tools/gen_config_doc.py)15
-rwxr-xr-xtools/recover.py49
-rwxr-xr-xtools/test-commands.py6
-rwxr-xr-xtools/test-generator.py15
-rwxr-xr-xtools/test-integration.py83
-rwxr-xr-xtools/test-map.py13
-rwxr-xr-xtools/test-performance.py2
-rwxr-xr-xtools/test-trips.py6
m---------traccar-web0
1270 files changed, 25548 insertions, 12770 deletions
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 03a3831b9..ba524068f 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -36,7 +36,7 @@ Provide as much details as possible, including log fragments, operating system a
Before creating a feature request make sure that the feature or modification that you are requesting is not yet implemented.
-Search reposiroty to ensure that there is no existing issues for your request. If there is, add a new comment on that issue.
+Search repository to ensure that there is no existing issues for your request. If there is, add a new comment on that issue.
Provide as much details as possible, including use case for your feature and any benefits that you can think of.
diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index 42721d3fc..cbe2721bb 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -10,12 +10,12 @@ jobs:
build:
runs-on: ubuntu-latest
-
+
steps:
- - uses: actions/checkout@v2
- - name: Set up JDK 11
- uses: actions/setup-java@v1
+ - uses: actions/checkout@v3
+ - uses: actions/setup-java@v3
with:
+ distribution: zulu
java-version: 11
- - name: Build with Gradle
- run: ./gradlew build --warning-mode=fail
+ cache: gradle
+ - run: ./gradlew build --no-daemon --warning-mode=fail
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 000000000..a8e4c5369
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,61 @@
+name: Build Installers
+
+on:
+ workflow_dispatch:
+ inputs:
+ version:
+ description: 'Version'
+ required: true
+ default: 'preview'
+
+jobs:
+ build:
+
+ runs-on: ubuntu-22.04
+
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ submodules: true
+ - run: git checkout ${{ github.ref_name }}
+ working-directory: ./traccar-web
+ - uses: actions/setup-java@v3
+ with:
+ distribution: temurin
+ java-version: 17
+ cache: gradle
+ - run: ./gradlew build
+ - uses: actions/setup-node@v3
+ with:
+ node-version: 18
+ cache: npm
+ cache-dependency-path: |
+ traccar-web/package-lock.json
+ traccar-web/modern/package-lock.json
+ - run: |
+ wget -q https://trials.sencha.com/cmd/7.6.0/SenchaCmd-7.6.0.87-linux-amd64.sh.zip
+ unzip SenchaCmd-*.zip
+ ./SenchaCmd-*.sh -q
+ echo "$HOME/bin/Sencha/Cmd/" >> $GITHUB_PATH
+ - run: ./traccar-web/tools/package.sh
+ - run: |
+ sudo dpkg --add-architecture i386
+ sudo apt-get update
+ sudo apt-get install libgcc-s1:i386 libstdc++6:i386
+ sudo apt-get install innoextract makeself wine32 s3cmd
+ - name: Build installers
+ working-directory: ./setup
+ run: |
+ wget -q http://files.jrsoftware.org/is/5/isetup-5.5.6.exe
+ wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_x64_windows_hotspot_17.0.6_10.zip
+ wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_x64_linux_hotspot_17.0.6_10.tar.gz
+ wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_arm_linux_hotspot_17.0.6_10.tar.gz
+ wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.6_10.tar.gz
+ ./package.sh ${{ github.event.inputs.version }}
+ - name: Upload installers
+ working-directory: ./setup
+ env:
+ S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }}
+ S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }}
+ run: s3cmd --acl-public put traccar-*.zip s3://traccar/builds/ --host=nyc3.digitaloceanspaces.com --host-bucket=traccar --access_key="$S3_ACCESS_KEY" --secret_key="$S3_SECRET_KEY"
diff --git a/.gitignore b/.gitignore
index c005ef9e4..2d03a9625 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,5 @@ nbactions.xml
.gradle
out
build
+.vscode
+bin
diff --git a/build.gradle b/build.gradle
index 0b3f54355..06516794c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,59 +1,64 @@
plugins {
id "java"
id "checkstyle"
- id "com.google.protobuf" version "0.8.18"
- id "org.kordamp.gradle.project-enforcer" version "0.9.0"
+ id "com.google.protobuf" version "0.9.3"
+ id "org.kordamp.gradle.project-enforcer" version "0.13.0"
}
repositories {
mavenCentral()
}
-ext {
- guiceVersion = "5.0.1"
- jettyVersion = "10.0.7" // jetty 11 javax to jakarta
- jerseyVersion = "2.35" // jersey 3 javax to jakarta
- jacksonVersion = "2.12.2" // same version as jersey-media-json-jackson dependency
- protobufVersion = "3.19.3"
-}
-
sourceCompatibility = "11"
compileJava.options.encoding = "UTF-8"
jar.destinationDirectory = file("$projectDir/target")
checkstyle {
- toolVersion = "9.2.1"
+ toolVersion = "10.12.0"
configFile = "gradle/checkstyle.xml" as File
checkstyleTest.enabled = false
}
-protobuf {
- protoc {
- artifact = "com.google.protobuf:protoc:$protobufVersion"
- }
-}
-
enforce {
rule(enforcer.rules.EnforceBytecodeVersion) { r ->
r.maxJdkVersion = "11"
}
}
+ext {
+ guiceVersion = "7.0.0"
+ jettyVersion = "11.0.15"
+ jerseyVersion = "3.1.3"
+ jacksonVersion = "2.15.2" // same version as jersey-media-json-jackson dependency
+ protobufVersion = "3.24.0"
+ jxlsVersion = "2.13.0"
+ junitVersion = "5.10.0"
+}
+
+protobuf {
+ protoc {
+ artifact = "com.google.protobuf:protoc:$protobufVersion"
+ }
+}
+
dependencies {
- implementation "commons-codec:commons-codec:1.15"
- implementation "com.h2database:h2:2.0.206"
- implementation "mysql:mysql-connector-java:8.0.27"
- implementation "org.postgresql:postgresql:42.3.1"
- implementation "com.microsoft.sqlserver:mssql-jdbc:9.4.1.jre11"
+ implementation "commons-codec:commons-codec:1.16.0"
+ implementation "com.h2database:h2:2.2.220"
+ implementation "com.mysql:mysql-connector-j:8.1.0"
+ implementation "org.mariadb.jdbc:mariadb-java-client:3.1.4"
+ implementation "org.postgresql:postgresql:42.6.0"
+ implementation "com.microsoft.sqlserver:mssql-jdbc:12.4.0.jre11"
implementation "com.zaxxer:HikariCP:5.0.1"
- implementation "io.netty:netty-all:4.1.66.Final"
- implementation "org.slf4j:slf4j-jdk14:2.0.0-alpha6"
+ implementation "io.netty:netty-all:4.1.96.Final"
+ implementation "org.slf4j:slf4j-jdk14:2.0.7"
implementation "com.google.inject:guice:$guiceVersion"
- implementation "com.google.inject.extensions:guice-assistedinject:$guiceVersion"
+ implementation "com.google.inject.extensions:guice-servlet:$guiceVersion"
implementation "org.owasp.encoder:encoder:1.2.3"
- implementation "org.glassfish:javax.json:1.1.4"
+ implementation "org.glassfish:jakarta.json:2.0.1"
+ implementation "com.sun.mail:jakarta.mail:2.0.1"
implementation "org.eclipse.jetty:jetty-server:$jettyVersion"
implementation "org.eclipse.jetty:jetty-servlet:$jettyVersion"
+ implementation "org.eclipse.jetty:jetty-servlets:$jettyVersion"
implementation "org.eclipse.jetty:jetty-webapp:$jettyVersion"
implementation "org.eclipse.jetty:jetty-jndi:$jettyVersion"
implementation "org.eclipse.jetty:jetty-proxy:$jettyVersion"
@@ -61,28 +66,37 @@ dependencies {
implementation "org.glassfish.jersey.containers:jersey-container-servlet:$jerseyVersion"
implementation "org.glassfish.jersey.media:jersey-media-json-jackson:$jerseyVersion"
implementation "org.glassfish.jersey.inject:jersey-hk2:$jerseyVersion"
- implementation "org.glassfish.hk2:guice-bridge:2.6.1" // same version as jersey-hk2
+ implementation "org.glassfish.hk2:guice-bridge:3.0.4" // same version as jersey-hk2
implementation "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion"
- implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr353:$jacksonVersion"
- implementation "org.liquibase:liquibase-core:4.7.0"
- implementation "com.sun.mail:javax.mail:1.6.2"
- implementation "org.jxls:jxls:2.4.7" // needs upgrade (wait for jexl 4)
- implementation "org.jxls:jxls-poi:1.0.16" // needs upgrade (wait for jexl 4)
- implementation "org.apache.velocity:velocity:1.7"
- implementation "org.apache.velocity:velocity-tools:2.0"
+ implementation "com.fasterxml.jackson.datatype:jackson-datatype-jakarta-jsonp:$jacksonVersion"
+ implementation "org.liquibase:liquibase-core:4.23.1"
+ implementation "org.apache.commons:commons-jexl3:3.3"
+ implementation "org.jxls:jxls:$jxlsVersion"
+ implementation "org.jxls:jxls-poi:$jxlsVersion"
+ implementation "org.apache.velocity:velocity-engine-core:2.3"
+ implementation "org.apache.velocity.tools:velocity-tools-generic:3.1"
implementation "org.apache.commons:commons-collections4:4.4"
- implementation "org.mnode.ical4j:ical4j:3.1.2"
+ implementation "org.mnode.ical4j:ical4j:3.2.12"
implementation "org.locationtech.spatial4j:spatial4j:0.8"
- implementation "org.locationtech.jts:jts-core:1.18.2"
- implementation "net.java.dev.jna:jna-platform:5.10.0"
- implementation "com.github.jnr:jnr-posix:3.1.15"
+ implementation "org.locationtech.jts:jts-core:1.19.0"
+ implementation "net.java.dev.jna:jna-platform:5.13.0"
+ implementation "com.github.jnr:jnr-posix:3.1.17"
implementation "com.google.protobuf:protobuf-java:$protobufVersion"
- implementation "javax.xml.bind:jaxb-api:2.3.1"
- implementation "com.sun.xml.bind:jaxb-core:3.0.2"
- implementation "com.sun.xml.bind:jaxb-impl:3.0.2"
implementation "javax.activation:activation:1.1.1"
- implementation "com.amazonaws:aws-java-sdk-sns:1.12.141"
- testImplementation "junit:junit:4.13.2"
+ implementation "com.amazonaws:aws-java-sdk-sns:1.12.532"
+ implementation "org.apache.kafka:kafka-clients:3.5.1"
+ implementation "com.hivemq:hivemq-mqtt-client:1.3.1"
+ implementation "redis.clients:jedis:4.4.3"
+ implementation "com.google.firebase:firebase-admin:9.2.0"
+ implementation "com.nimbusds:oauth2-oidc-sdk:10.13.2"
+ implementation "com.rabbitmq:amqp-client:5.18.0"
+ testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
+ testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
+ testImplementation "org.mockito:mockito-core:5.4.0"
+}
+
+test {
+ useJUnitPlatform()
}
task copyDependencies(type: Copy) {
@@ -95,7 +109,7 @@ jar {
manifest {
attributes(
"Main-Class": "org.traccar.Main",
- "Implementation-Version": "4.15",
+ "Implementation-Version": "5.8",
"Class-Path": configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(" "))
}
}
diff --git a/debug.xml b/debug.xml
index f9515bb2b..2569bb8cd 100644
--- a/debug.xml
+++ b/debug.xml
@@ -10,7 +10,14 @@
<entry key='web.debug'>true</entry>
<entry key='web.console'>true</entry>
+ <entry key='geocoder.type'>test</entry>
+
+ <entry key='media.path'>./target/media</entry>
+
<entry key='logger.console'>true</entry>
+ <entry key='logger.queries'>false</entry>
+
+ <entry key='mail.debug'>true</entry>
<entry key='database.driver'>org.h2.Driver</entry>
<entry key='database.url'>jdbc:h2:./target/database</entry>
diff --git a/gradle/checkstyle.xml b/gradle/checkstyle.xml
index 9d30e53d6..bb89450d6 100644
--- a/gradle/checkstyle.xml
+++ b/gradle/checkstyle.xml
@@ -79,7 +79,9 @@
<!--<module name="MethodLength">
<property name="max" value="200"/>
</module>-->
- <module name="ParameterNumber"/>
+ <module name="ParameterNumber">
+ <property name="tokens" value="METHOD_DEF"/>
+ </module>
<!-- Checks for whitespace -->
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
@@ -112,7 +114,7 @@
<module name="EmptyStatement"/>
<module name="EqualsHashCode"/>
<module name="IllegalInstantiation"/>
- <module name="InnerAssignment"/>
+ <!--<module name="InnerAssignment"/>-->
<module name="MissingSwitchDefault"/>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
@@ -122,7 +124,9 @@
<module name="FinalClass"/>
<module name="HideUtilityClassConstructor"/>
<module name="InterfaceIsType"/>
- <module name="VisibilityModifier"/>
+ <module name="VisibilityModifier">
+ <property name="protectedAllowed" value="true"/>
+ </module>
<!-- Miscellaneous other checks. -->
<!-- See http://checkstyle.sf.net/config_misc.html -->
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 00e33edef..ae04661ee 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/schema/changelog-4.0-clean.xml b/schema/changelog-4.0-clean.xml
index f3f814eba..b4d8ac0ba 100644
--- a/schema/changelog-4.0-clean.xml
+++ b/schema/changelog-4.0-clean.xml
@@ -620,14 +620,6 @@
<column name="zoom" valueNumeric="0" />
</insert>
- <insert tableName="tc_users">
- <column name="name" value="admin" />
- <column name="email" value="admin" />
- <column name="hashedpassword" value="D33DCA55ABD4CC5BC76F2BC0B4E603FE2C6F61F4C1EF2D47" />
- <column name="salt" value="000000000000000000000000000000000000000000000000" />
- <column name="administrator" valueBoolean="true" />
- </insert>
-
</changeSet>
<changeSet author="author" id="changelog-4.0-clean-common">
diff --git a/schema/changelog-4.16.xml b/schema/changelog-5.0.xml
index 8bf3a41d5..0e8474eef 100644
--- a/schema/changelog-4.16.xml
+++ b/schema/changelog-5.0.xml
@@ -4,9 +4,15 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"
- logicalFilePath="changelog-4.16">
+ logicalFilePath="changelog-5.0">
- <changeSet author="author" id="changelog-4.16">
+ <changeSet author="author" id="changelog-5.0">
+
+ <preConditions onFail="MARK_RAN">
+ <not>
+ <columnExists tableName="tc_servers" columnName="disablereports" />
+ </not>
+ </preConditions>
<addColumn tableName="tc_servers">
<column name="disablereports" type="BOOLEAN" defaultValueBoolean="false" />
diff --git a/schema/changelog-5.1.xml b/schema/changelog-5.1.xml
new file mode 100644
index 000000000..e972813f6
--- /dev/null
+++ b/schema/changelog-5.1.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<databaseChangeLog
+ xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
+ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"
+ logicalFilePath="changelog-5.1">
+
+ <changeSet author="author" id="changelog-5.1">
+
+ <createIndex tableName="tc_drivers" indexName="idx_drivers_uniqueid">
+ <column name="uniqueid" />
+ </createIndex>
+
+ <createIndex tableName="tc_devices" indexName="idx_devices_uniqueid">
+ <column name="uniqueid" />
+ </createIndex>
+
+ <createIndex tableName="tc_users" indexName="idx_users_email">
+ <column name="email" />
+ </createIndex>
+
+ <createIndex tableName="tc_users" indexName="idx_users_login">
+ <column name="login" />
+ </createIndex>
+
+ <createIndex tableName="tc_users" indexName="idx_users_token">
+ <column name="token" />
+ </createIndex>
+
+ <addColumn tableName="tc_servers">
+ <column name="overlayurl" type="VARCHAR(512)" />
+ </addColumn>
+
+ </changeSet>
+
+</databaseChangeLog>
diff --git a/schema/changelog-5.2.xml b/schema/changelog-5.2.xml
new file mode 100644
index 000000000..687024f52
--- /dev/null
+++ b/schema/changelog-5.2.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<databaseChangeLog
+ xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
+ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"
+ logicalFilePath="changelog-5.2">
+
+ <changeSet author="author" id="changelog-5.2">
+
+ <addColumn tableName="tc_devices">
+ <column name="status" type="CHAR(8)" />
+ </addColumn>
+
+ <addColumn tableName="tc_devices">
+ <column name="geofenceids" type="VARCHAR(128)" />
+ </addColumn>
+
+ </changeSet>
+
+</databaseChangeLog>
diff --git a/schema/changelog-5.3.xml b/schema/changelog-5.3.xml
new file mode 100644
index 000000000..1e5a6005a
--- /dev/null
+++ b/schema/changelog-5.3.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<databaseChangeLog
+ xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
+ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"
+ logicalFilePath="changelog-5.3">
+
+ <changeSet author="author" id="changelog-5.3">
+
+ <addColumn tableName="tc_servers">
+ <column name="fixedemail" type="BOOLEAN" defaultValueBoolean="false" />
+ </addColumn>
+
+ <addColumn tableName="tc_users">
+ <column name="fixedemail" type="BOOLEAN" defaultValueBoolean="false" />
+ </addColumn>
+
+ <addColumn tableName="tc_devices">
+ <column name="expirationtime" type="TIMESTAMP" />
+ </addColumn>
+
+ <createTable tableName="tc_keystore">
+ <column autoIncrement="true" name="id" type="INT">
+ <constraints primaryKey="true" />
+ </column>
+ <column name="publickey" type="MEDIUMBLOB">
+ <constraints nullable="false" />
+ </column>
+ <column name="privatekey" type="MEDIUMBLOB">
+ <constraints nullable="false" />
+ </column>
+ </createTable>
+
+ <dropIndex indexName="idx_users_token" tableName="tc_users" />
+
+ <dropColumn tableName="tc_users" columnName="token" />
+
+ </changeSet>
+
+</databaseChangeLog>
diff --git a/schema/changelog-5.4.xml b/schema/changelog-5.4.xml
new file mode 100644
index 000000000..e69bc5fab
--- /dev/null
+++ b/schema/changelog-5.4.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<databaseChangeLog
+ xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
+ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"
+ logicalFilePath="changelog-5.4">
+
+ <changeSet author="author" id="changelog-5.4">
+
+ <addColumn tableName="tc_devices">
+ <column name="motionstate" type="BOOLEAN" defaultValueBoolean="false" />
+ <column name="motiontime" type="TIMESTAMP" />
+ <column name="motiondistance" type="DOUBLE" defaultValueNumeric="0" />
+ <column name="overspeedstate" type="BOOLEAN" defaultValueBoolean="false" />
+ <column name="overspeedtime" type="TIMESTAMP" />
+ <column name="overspeedgeofenceid" type="INT" defaultValueNumeric="0" />
+ </addColumn>
+
+ <createTable tableName="tc_commands_queue">
+ <column autoIncrement="true" name="id" type="INT">
+ <constraints primaryKey="true" />
+ </column>
+ <column name="deviceid" type="INT">
+ <constraints nullable="false" />
+ </column>
+ <column name="description" type="VARCHAR(4000)">
+ <constraints nullable="false" />
+ </column>
+ <column name="type" type="VARCHAR(128)">
+ <constraints nullable="false" />
+ </column>
+ <column name="textchannel" type="BOOLEAN" defaultValueBoolean="false">
+ <constraints nullable="false" />
+ </column>
+ <column name="attributes" type="VARCHAR(4000)">
+ <constraints nullable="false" />
+ </column>
+ </createTable>
+
+ <addForeignKeyConstraint
+ baseTableName="tc_commands_queue"
+ baseColumnNames="deviceid"
+ constraintName="fk_commands_queue_deviceid"
+ onDelete="CASCADE"
+ referencedColumnNames="id"
+ referencedTableName="tc_devices" />
+
+ <createIndex tableName="tc_commands_queue" indexName="idx_commands_queue_deviceid">
+ <column name="deviceid" />
+ </createIndex>
+
+ </changeSet>
+
+</databaseChangeLog>
diff --git a/schema/changelog-5.5.xml b/schema/changelog-5.5.xml
new file mode 100644
index 000000000..4f5b210c5
--- /dev/null
+++ b/schema/changelog-5.5.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<databaseChangeLog
+ xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
+ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"
+ logicalFilePath="changelog-5.5">
+
+ <changeSet author="author" id="changelog-5.5">
+
+ <dropColumn tableName="tc_commands_queue" columnName="description" />
+
+ </changeSet>
+
+</databaseChangeLog>
diff --git a/schema/changelog-5.6.xml b/schema/changelog-5.6.xml
new file mode 100644
index 000000000..dc302c6a4
--- /dev/null
+++ b/schema/changelog-5.6.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<databaseChangeLog
+ xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
+ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"
+ logicalFilePath="changelog-5.6">
+
+ <changeSet author="author" id="changelog-5.6">
+
+ <addColumn tableName="tc_devices">
+ <column name="motionstreak" type="BOOLEAN" defaultValueBoolean="false" />
+ </addColumn>
+
+ <createTable tableName="tc_reports">
+ <column name="id" type="INT" autoIncrement="true">
+ <constraints primaryKey="true" />
+ </column>
+ <column name="type" type="VARCHAR(32)">
+ <constraints nullable="false" />
+ </column>
+ <column name="description" type="VARCHAR(128)">
+ <constraints nullable="false" />
+ </column>
+ <column name="calendarid" type="INT">
+ <constraints nullable="false" />
+ </column>
+ <column name="attributes" type="VARCHAR(4000)">
+ <constraints nullable="false" />
+ </column>
+ </createTable>
+
+ <addForeignKeyConstraint baseTableName="tc_reports" baseColumnNames="calendarid" constraintName="fk_reports_calendarid" referencedTableName="tc_calendars" referencedColumnNames="id" onDelete="CASCADE" />
+
+ <createTable tableName="tc_user_report">
+ <column name="userid" type="INT">
+ <constraints nullable="false" />
+ </column>
+ <column name="reportid" type="INT">
+ <constraints nullable="false" />
+ </column>
+ </createTable>
+
+ <addForeignKeyConstraint baseTableName="tc_user_report" baseColumnNames="userid" constraintName="fk_user_report_userid" referencedTableName="tc_users" referencedColumnNames="id" onDelete="CASCADE" />
+ <addForeignKeyConstraint baseTableName="tc_user_report" baseColumnNames="reportid" constraintName="fk_user_report_reportid" referencedTableName="tc_reports" referencedColumnNames="id" onDelete="CASCADE" />
+
+ <createTable tableName="tc_group_report">
+ <column name="groupid" type="INT">
+ <constraints nullable="false" />
+ </column>
+ <column name="reportid" type="INT">
+ <constraints nullable="false" />
+ </column>
+ </createTable>
+
+ <addForeignKeyConstraint baseTableName="tc_group_report" baseColumnNames="groupid" constraintName="fk_group_report_groupid" referencedTableName="tc_groups" referencedColumnNames="id" onDelete="CASCADE" />
+ <addForeignKeyConstraint baseTableName="tc_group_report" baseColumnNames="reportid" constraintName="fk_group_report_reportid" referencedTableName="tc_reports" referencedColumnNames="id" onDelete="CASCADE" />
+
+ <createTable tableName="tc_device_report">
+ <column name="deviceid" type="INT">
+ <constraints nullable="false" />
+ </column>
+ <column name="reportid" type="INT">
+ <constraints nullable="false" />
+ </column>
+ </createTable>
+
+ <addForeignKeyConstraint baseTableName="tc_device_report" baseColumnNames="deviceid" constraintName="fk_device_report_deviceid" referencedTableName="tc_devices" referencedColumnNames="id" onDelete="CASCADE" />
+ <addForeignKeyConstraint baseTableName="tc_device_report" baseColumnNames="reportid" constraintName="fk_device_report_reportid" referencedTableName="tc_reports" referencedColumnNames="id" onDelete="CASCADE" />
+
+ </changeSet>
+
+</databaseChangeLog>
diff --git a/schema/changelog-5.7.xml b/schema/changelog-5.7.xml
new file mode 100644
index 000000000..ad15ac48c
--- /dev/null
+++ b/schema/changelog-5.7.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<databaseChangeLog
+ xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
+ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"
+ logicalFilePath="changelog-5.7">
+
+ <changeSet author="author" id="changelog-5.7">
+
+ <addColumn tableName="tc_notifications">
+ <column name="commandid" type="INT" />
+ </addColumn>
+
+ <addForeignKeyConstraint
+ baseTableName="tc_notifications"
+ baseColumnNames="commandid"
+ constraintName="fk_notifications_commandid"
+ referencedTableName="tc_commands"
+ referencedColumnNames="id"
+ onDelete="CASCADE" />
+
+ </changeSet>
+
+</databaseChangeLog>
diff --git a/schema/changelog-5.8.xml b/schema/changelog-5.8.xml
new file mode 100644
index 000000000..ec54bf17f
--- /dev/null
+++ b/schema/changelog-5.8.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<databaseChangeLog
+ xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
+ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"
+ logicalFilePath="changelog-5.8">
+
+ <changeSet author="author" id="changelog-5.8">
+
+ <dropColumn tableName="tc_devices" columnName="geofenceids" />
+ <addColumn tableName="tc_positions">
+ <column name="geofenceids" type="VARCHAR(128)" />
+ </addColumn>
+
+ </changeSet>
+
+</databaseChangeLog>
diff --git a/schema/changelog-5.9.xml b/schema/changelog-5.9.xml
new file mode 100644
index 000000000..50a3d3aaa
--- /dev/null
+++ b/schema/changelog-5.9.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<databaseChangeLog
+ xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
+ http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd"
+ logicalFilePath="changelog-5.9">
+
+ <changeSet author="author" id="changelog-5.9">
+
+ <addColumn tableName="tc_devices">
+ <column name="calendarid" type="INT" />
+ </addColumn>
+
+ <addForeignKeyConstraint
+ baseTableName="tc_devices"
+ baseColumnNames="calendarid"
+ constraintName="fk_devices_calendarid"
+ referencedTableName="tc_calendars"
+ referencedColumnNames="id"
+ onDelete="SET NULL"
+ onUpdate="RESTRICT"
+ />
+
+ </changeSet>
+
+</databaseChangeLog>
diff --git a/schema/changelog-master.xml b/schema/changelog-master.xml
index d79e084f6..331d5ec78 100644
--- a/schema/changelog-master.xml
+++ b/schema/changelog-master.xml
@@ -29,6 +29,16 @@
<include file="changelog-4.11.xml" relativeToChangelogFile="true" />
<include file="changelog-4.13.xml" relativeToChangelogFile="true" />
<include file="changelog-4.15.xml" relativeToChangelogFile="true" />
- <include file="changelog-4.16.xml" relativeToChangelogFile="true" />
+
+ <include file="changelog-5.0.xml" relativeToChangelogFile="true" />
+ <include file="changelog-5.1.xml" relativeToChangelogFile="true" />
+ <include file="changelog-5.2.xml" relativeToChangelogFile="true" />
+ <include file="changelog-5.3.xml" relativeToChangelogFile="true" />
+ <include file="changelog-5.4.xml" relativeToChangelogFile="true" />
+ <include file="changelog-5.5.xml" relativeToChangelogFile="true" />
+ <include file="changelog-5.6.xml" relativeToChangelogFile="true" />
+ <include file="changelog-5.7.xml" relativeToChangelogFile="true" />
+ <include file="changelog-5.8.xml" relativeToChangelogFile="true" />
+ <include file="changelog-5.9.xml" relativeToChangelogFile="true" />
</databaseChangeLog>
diff --git a/setup/cloud-init.yaml b/setup/cloud-init.yaml
new file mode 100644
index 000000000..1246fb1b7
--- /dev/null
+++ b/setup/cloud-init.yaml
@@ -0,0 +1,29 @@
+#cloud-config
+
+write_files:
+ - content: |
+ <?xml version='1.0' encoding='UTF-8'?>
+ <!DOCTYPE properties SYSTEM 'http://java.sun.com/dtd/properties.dtd'>
+ <properties>
+
+ <entry key="config.default">./conf/default.xml</entry>
+
+ <entry key='database.driver'>com.mysql.jdbc.Driver</entry>
+ <entry key='database.url'>jdbc:mysql://localhost/traccar?zeroDateTimeBehavior=round&amp;serverTimezone=UTC&amp;allowPublicKeyRetrieval=true&amp;useSSL=false&amp;allowMultiQueries=true&amp;autoReconnect=true&amp;useUnicode=yes&amp;characterEncoding=UTF-8&amp;sessionVariables=sql_mode=''</entry>
+ <entry key='database.user'>root</entry>
+ <entry key='database.password'>root</entry>
+
+ </properties>
+ path: /root/traccar.xml
+
+package_update: true
+packages:
+ - unzip
+ - mysql-server
+
+runcmd:
+ - mysql -u root --execute="ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root'; GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION; FLUSH PRIVILEGES; CREATE DATABASE traccar;"
+ - wget https://www.traccar.org/download/traccar-linux-64-latest.zip
+ - unzip traccar-linux-*.zip && ./traccar.run
+ - cp /root/traccar.xml /opt/traccar/conf/
+ - service traccar start
diff --git a/setup/default.xml b/setup/default.xml
index 71e14f501..576bfcb6c 100644
--- a/setup/default.xml
+++ b/setup/default.xml
@@ -11,12 +11,12 @@
-->
<entry key='web.port'>8082</entry>
- <entry key='web.path'>./web</entry>
+ <entry key='web.path'>./modern</entry>
+ <entry key='web.sanitize'>false</entry>
<entry key='web.persistSession'>false</entry>
<entry key='geocoder.enable'>true</entry>
- <entry key='geocoder.type'>nominatim</entry>
- <entry key='geocoder.url'>https://us1.locationiq.com/v1/reverse.php</entry>
+ <entry key='geocoder.type'>locationiq</entry>
<entry key='geocoder.key'>pk.689d849289c8c63708068b2ff1f63b2d</entry>
<entry key='geocoder.onRequest'>true</entry>
<entry key='geocoder.ignorePositions'>true</entry>
@@ -29,12 +29,10 @@
<entry key='filter.future'>86400</entry>
<entry key='event.ignoreDuplicateAlerts'>true</entry>
- <entry key='processing.computedAttributes.enable'>true</entry>
- <entry key='processing.engineHours.enable'>true</entry>
<entry key='media.path'>./media</entry>
- <entry key='notificator.types'>web,mail</entry>
+ <entry key='notificator.types'>web,mail,command</entry>
<entry key='server.statistics'>https://www.traccar.org/analytics/</entry>
@@ -284,5 +282,13 @@
<entry key='armoli.port'>5238</entry>
<entry key='teratrack.port'>5239</entry>
<entry key='envotech.port'>5240</entry>
+ <entry key='bstpl.port'>5241</entry>
+ <entry key='thuraya.port'>5242</entry>
+ <entry key='ndtpv6.port'>5243</entry>
+ <entry key='g1rus.port'>5244</entry>
+ <entry key='rftrack.port'>5245</entry>
+ <entry key='vlt.port'>5246</entry>
+ <entry key='transync.port'>5247</entry>
+ <entry key='t622iridium.port'>5248</entry>
</properties>
diff --git a/setup/environment.sh b/setup/environment.sh
deleted file mode 100644
index 86a50cc85..000000000
--- a/setup/environment.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env bash
-
-add-apt-repository ppa:openjdk-r/ppa
-curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
-dpkg --add-architecture i386
-apt update
-apt install -y git openjdk-11-jdk zip unzip innoextract wine wine32 makeself nodejs
-
-# /usr/bin/printf '\xfe\xed\xfe\xed\x00\x00\x00\x02\x00\x00\x00\x00\xe2\x68\x6e\x45\xfb\x43\xdf\xa4\xd9\x92\xdd\x41\xce\xb6\xb2\x1c\x63\x30\xd7\x92' > /etc/ssl/certs/java/cacerts
-# /var/lib/dpkg/info/ca-certificates-java.postinst configure
-
-git clone --recurse-submodules https://github.com/traccar/traccar.git
-(cd traccar/traccar-web && git checkout master)
-(cd traccar && ./gradlew build)
-
-wget http://cdn.sencha.com/cmd/7.1.0.15/no-jre/SenchaCmd-7.1.0.15-linux-i386.sh.zip
-unzip SenchaCmd-*.zip ; rm SenchaCmd-*.zip
-./SenchaCmd-*.sh -q ; rm SenchaCmd-*
-export PATH=$PATH:~/bin/Sencha/Cmd/
-
-(cd traccar/traccar-web && ./tools/package.sh)
-
-cd traccar/setup
-wget http://files.jrsoftware.org/is/5/isetup-5.5.6.exe
-wget https://github.com/ojdkbuild/ojdkbuild/releases/download/java-11-openjdk-11.0.13.8-1/java-11-openjdk-11.0.13.8-1.windows.ojdkbuild.x86_64.zip
-wget https://github.com/ojdkbuild/contrib_jdk11u-ci/releases/download/jdk-11.0.13%2B8/jdk-11.0.13-ojdkbuild-linux-x64.zip
-wget https://github.com/ojdkbuild/contrib_jdk11u-arm32-ci/releases/download/jdk-11.0.13%2B8/jdk-11.0.13-ojdkbuild-linux-armhf.zip
diff --git a/setup/package.sh b/setup/package.sh
index e5f976b79..f8ec927eb 100755
--- a/setup/package.sh
+++ b/setup/package.sh
@@ -15,6 +15,7 @@ usage () {
echo "Available platforms:"
echo " * linux-64"
echo " * linux-arm"
+ echo " * linux-arm64"
echo " * windows-64"
echo " * other"
exit 1
@@ -61,17 +62,20 @@ fi
if [ $PLATFORM = "all" -o $PLATFORM = "windows-64" ]; then
check_requirement "Inno Extractor" "which innoextract" "Missing innoextract binary"
check_requirement "Inno Setup" "ls i*setup-*.exe" "Missing Inno Setup (http://www.jrsoftware.org/isdl.php)"
- check_requirement "Windows 64 Java" "ls java-*.windows.ojdkbuild.x86_64.zip" "Missing Windows 64 Java (https://github.com/ojdkbuild/ojdkbuild)"
+ check_requirement "Windows 64 Java" "ls OpenJDK*64_windows*.zip" "Missing Windows 64 JDK (https://adoptium.net/)"
check_requirement "Wine" "which wine" "Missing wine binary"
fi
-if [ $PLATFORM = "all" -o $PLATFORM = "linux-64" -o $PLATFORM = "linux-arm" ]; then
+if [ $PLATFORM = "all" -o $PLATFORM = "linux-64" -o $PLATFORM = "linux-arm" -o $PLATFORM = "linux-arm64" ]; then
check_requirement "Makeself" "which makeself" "Missing makeself binary"
fi
if [ $PLATFORM = "all" -o $PLATFORM = "linux-64" ]; then
- check_requirement "Linux 64 Java" "ls jdk-*-linux-x64.zip" "Missing Linux 64 Java (https://github.com/ojdkbuild/contrib_jdk11u-ci/releases)"
+ check_requirement "Linux 64 Java" "ls OpenJDK*x64_linux*.tar.gz" "Missing Linux 64 JDK (https://adoptium.net/)"
fi
if [ $PLATFORM = "all" -o $PLATFORM = "linux-arm" ]; then
- check_requirement "Linux ARM Java" "ls jdk-*-linux-armhf.zip" "Missing Linux ARM Java (https://github.com/ojdkbuild/contrib_jdk11u-aarch32-ci/releases)"
+ check_requirement "Linux ARM Java" "ls OpenJDK*arm_linux*.tar.gz" "Missing Linux ARM JDK (https://adoptium.net/)"
+fi
+if [ $PLATFORM = "all" -o $PLATFORM = "linux-arm64" ]; then
+ check_requirement "Linux ARM 64 Java" "ls OpenJDK*aarch64_linux*.tar.gz" "Missing Linux ARM 64 JDK (https://adoptium.net/)"
fi
if [ $PREREQ = false ]; then
info "Missing build requirements, aborting..."
@@ -81,13 +85,14 @@ else
fi
prepare () {
- mkdir -p out/{conf,data,lib,logs,web,schema,templates}
+ mkdir -p out/{conf,data,lib,logs,legacy,modern,schema,templates}
cp ../target/tracker-server.jar out
cp ../target/lib/* out/lib
cp ../schema/* out/schema
cp -r ../templates/* out/templates
- cp -r ../traccar-web/web/* out/web
+ cp -r ../traccar-web/web/* out/legacy
+ cp -r ../traccar-web/modern/build/* out/modern
cp default.xml out/conf
cp traccar.xml out/conf
@@ -118,9 +123,9 @@ package_other () {
package_windows () {
info "Building Windows 64 installer"
- unzip -q -o java-*.windows.ojdkbuild.x86_64.zip
- jlink --module-path java-*.windows.ojdkbuild.x86_64/jmods --add-modules java.se,jdk.charsets,jdk.crypto.ec --output out/jre
- rm -rf java-*.windows.ojdkbuild.x86_64
+ unzip -q OpenJDK*64_windows*.zip
+ jlink --module-path jdk-*/jmods --add-modules java.se,jdk.charsets,jdk.crypto.ec,jdk.unsupported --output out/jre
+ rm -rf jdk-*
wine app/ISCC.exe traccar.iss >/dev/null
rm -rf out/jre
zip -q -j traccar-windows-64-$VERSION.zip Output/traccar-setup.exe README.txt
@@ -132,13 +137,13 @@ package_linux () {
cp setup.sh out
cp traccar.service out
- unzip -q -o jdk-*-linux-$1.zip
- jlink --module-path jdk-*-linux-$1/jmods --add-modules java.se,jdk.charsets,jdk.crypto.ec --output out/jre
- rm -rf jdk-*-linux-$1
+ tar -xf OpenJDK*$2_linux*.tar.gz
+ jlink --module-path jdk-*/jmods --add-modules java.se,jdk.charsets,jdk.crypto.ec,jdk.unsupported --output out/jre
+ rm -rf jdk-*
makeself --needroot --quiet --notemp out traccar.run "traccar" ./setup.sh
rm -rf out/jre
- zip -q -j traccar-linux-$2-$VERSION.zip traccar.run README.txt
+ zip -q -j traccar-linux-$1-$VERSION.zip traccar.run README.txt
rm traccar.run
rm out/setup.sh
@@ -147,22 +152,29 @@ package_linux () {
package_linux_64 () {
info "Building Linux 64 installer"
- package_linux x64 64
+ package_linux 64 x64
ok "Created Linux 64 installer"
}
package_linux_arm () {
info "Building Linux ARM installer"
- package_linux armhf arm
+ package_linux arm arm
ok "Created Linux ARM installer"
}
+package_linux_arm64 () {
+ info "Building Linux ARM 64 installer"
+ package_linux arm64 aarch64
+ ok "Created Linux ARM 64 installer"
+}
+
prepare
case $PLATFORM in
all)
package_linux_64
package_linux_arm
+ package_linux_arm64
package_windows
package_other
;;
@@ -175,6 +187,10 @@ case $PLATFORM in
package_linux_arm
;;
+ linux-arm64)
+ package_linux_arm64
+ ;;
+
windows-64)
package_windows
;;
diff --git a/setup/traccar.iss b/setup/traccar.iss
index 3ffab1289..f9988a6f3 100644
--- a/setup/traccar.iss
+++ b/setup/traccar.iss
@@ -1,6 +1,6 @@
[Setup]
AppName=Traccar
-AppVersion=4.15
+AppVersion=5.8
DefaultDirName={pf}\Traccar
OutputBaseFilename=traccar-setup
ArchitecturesInstallIn64BitMode=x64
diff --git a/src/main/java/org/traccar/BasePipelineFactory.java b/src/main/java/org/traccar/BasePipelineFactory.java
index 89ef76a80..5b48f3d15 100644
--- a/src/main/java/org/traccar/BasePipelineFactory.java
+++ b/src/main/java/org/traccar/BasePipelineFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
*/
package org.traccar;
+import com.google.inject.Injector;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInboundHandler;
@@ -22,7 +23,9 @@ import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOutboundHandler;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.timeout.IdleStateHandler;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
+import org.traccar.handler.AcknowledgementHandler;
import org.traccar.handler.ComputedAttributesHandler;
import org.traccar.handler.CopyAttributesHandler;
import org.traccar.handler.DefaultDataHandler;
@@ -30,9 +33,11 @@ import org.traccar.handler.DistanceHandler;
import org.traccar.handler.EngineHoursHandler;
import org.traccar.handler.FilterHandler;
import org.traccar.handler.GeocoderHandler;
+import org.traccar.handler.GeofenceHandler;
import org.traccar.handler.GeolocationHandler;
import org.traccar.handler.HemisphereHandler;
import org.traccar.handler.MotionHandler;
+import org.traccar.handler.NetworkForwarderHandler;
import org.traccar.handler.NetworkMessageHandler;
import org.traccar.handler.OpenChannelHandler;
import org.traccar.handler.RemoteAddressHandler;
@@ -43,10 +48,11 @@ import org.traccar.handler.events.AlertEventHandler;
import org.traccar.handler.events.BehaviorEventHandler;
import org.traccar.handler.events.CommandResultEventHandler;
import org.traccar.handler.events.DriverEventHandler;
-import org.traccar.handler.events.FuelDropEventHandler;
+import org.traccar.handler.events.FuelEventHandler;
import org.traccar.handler.events.GeofenceEventHandler;
import org.traccar.handler.events.IgnitionEventHandler;
import org.traccar.handler.events.MaintenanceEventHandler;
+import org.traccar.handler.events.MediaEventHandler;
import org.traccar.handler.events.MotionEventHandler;
import org.traccar.handler.events.OverspeedEventHandler;
@@ -54,16 +60,22 @@ import java.util.Map;
public abstract class BasePipelineFactory extends ChannelInitializer<Channel> {
+ private final Injector injector;
private final TrackerConnector connector;
+ private final Config config;
private final String protocol;
- private int timeout;
+ private final int timeout;
- public BasePipelineFactory(TrackerConnector connector, String protocol) {
+ public BasePipelineFactory(TrackerConnector connector, Config config, String protocol) {
+ this.injector = Main.getInjector();
this.connector = connector;
+ this.config = config;
this.protocol = protocol;
- timeout = Context.getConfig().getInteger(Keys.PROTOCOL_TIMEOUT.withPrefix(protocol));
+ int timeout = config.getInteger(Keys.PROTOCOL_TIMEOUT.withPrefix(protocol));
if (timeout == 0) {
- timeout = Context.getConfig().getInteger(Keys.SERVER_TIMEOUT);
+ this.timeout = config.getInteger(Keys.SERVER_TIMEOUT);
+ } else {
+ this.timeout = timeout;
}
}
@@ -75,7 +87,7 @@ public abstract class BasePipelineFactory extends ChannelInitializer<Channel> {
private void addHandlers(ChannelPipeline pipeline, Class<? extends ChannelHandler>... handlerClasses) {
for (Class<? extends ChannelHandler> handlerClass : handlerClasses) {
if (handlerClass != null) {
- pipeline.addLast(Main.getInjector().getInstance(handlerClass));
+ pipeline.addLast(injector.getInstance(handlerClass));
}
}
}
@@ -105,11 +117,22 @@ public abstract class BasePipelineFactory extends ChannelInitializer<Channel> {
pipeline.addLast(new IdleStateHandler(timeout, 0, 0));
}
pipeline.addLast(new OpenChannelHandler(connector));
+ if (config.hasKey(Keys.SERVER_FORWARD)) {
+ int port = config.getInteger(Keys.PROTOCOL_PORT.withPrefix(protocol));
+ var handler = new NetworkForwarderHandler(port);
+ injector.injectMembers(handler);
+ pipeline.addLast(handler);
+ }
pipeline.addLast(new NetworkMessageHandler());
pipeline.addLast(new StandardLoggingHandler(protocol));
+ if (!connector.isDatagram() && !config.getBoolean(Keys.SERVER_INSTANT_ACKNOWLEDGEMENT)) {
+ pipeline.addLast(new AcknowledgementHandler());
+ }
addProtocolHandlers(handler -> {
- if (!(handler instanceof BaseProtocolDecoder || handler instanceof BaseProtocolEncoder)) {
+ if (handler instanceof BaseProtocolDecoder || handler instanceof BaseProtocolEncoder) {
+ injector.injectMembers(handler);
+ } else {
if (handler instanceof ChannelInboundHandler) {
handler = new WrapperInboundHandler((ChannelInboundHandler) handler);
} else {
@@ -127,26 +150,27 @@ public abstract class BasePipelineFactory extends ChannelInitializer<Channel> {
DistanceHandler.class,
RemoteAddressHandler.class,
FilterHandler.class,
+ GeofenceHandler.class,
GeocoderHandler.class,
SpeedLimitHandler.class,
MotionHandler.class,
CopyAttributesHandler.class,
EngineHoursHandler.class,
ComputedAttributesHandler.class,
- WebDataHandler.class,
+ PositionForwardingHandler.class,
DefaultDataHandler.class,
+ MediaEventHandler.class,
CommandResultEventHandler.class,
OverspeedEventHandler.class,
BehaviorEventHandler.class,
- FuelDropEventHandler.class,
+ FuelEventHandler.class,
MotionEventHandler.class,
GeofenceEventHandler.class,
AlertEventHandler.class,
IgnitionEventHandler.class,
MaintenanceEventHandler.class,
- DriverEventHandler.class);
-
- pipeline.addLast(new MainEventHandler());
+ DriverEventHandler.class,
+ MainEventHandler.class);
}
}
diff --git a/src/main/java/org/traccar/BaseProtocol.java b/src/main/java/org/traccar/BaseProtocol.java
index 52d34dc44..ea302997c 100644
--- a/src/main/java/org/traccar/BaseProtocol.java
+++ b/src/main/java/org/traccar/BaseProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -21,7 +21,10 @@ import io.netty.channel.Channel;
import io.netty.handler.codec.string.StringEncoder;
import org.traccar.helper.DataConverter;
import org.traccar.model.Command;
+import org.traccar.sms.SmsManager;
+import jakarta.annotation.Nullable;
+import jakarta.inject.Inject;
import java.net.SocketAddress;
import java.util.Arrays;
import java.util.Collection;
@@ -37,6 +40,8 @@ public abstract class BaseProtocol implements Protocol {
private final Set<String> supportedTextCommands = new HashSet<>();
private final List<TrackerConnector> connectorList = new LinkedList<>();
+ private SmsManager smsManager;
+
private StringProtocolEncoder textCommandEncoder = null;
public static String nameFromClass(Class<?> clazz) {
@@ -48,6 +53,11 @@ public abstract class BaseProtocol implements Protocol {
name = nameFromClass(getClass());
}
+ @Inject
+ public void setSmsManager(@Nullable SmsManager smsManager) {
+ this.smsManager = smsManager;
+ }
+
@Override
public String getName() {
return name;
@@ -95,7 +105,8 @@ public abstract class BaseProtocol implements Protocol {
} else if (command.getType().equals(Command.TYPE_CUSTOM)) {
String data = command.getString(Command.KEY_DATA);
if (BasePipelineFactory.getHandler(channel.pipeline(), StringEncoder.class) != null) {
- channel.writeAndFlush(new NetworkMessage(data, remoteAddress));
+ channel.writeAndFlush(new NetworkMessage(
+ data.replace("\\r", "\r").replace("\\n", "\n"), remoteAddress));
} else {
ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(data));
channel.writeAndFlush(new NetworkMessage(buf, remoteAddress));
@@ -111,13 +122,13 @@ public abstract class BaseProtocol implements Protocol {
@Override
public void sendTextCommand(String destAddress, Command command) throws Exception {
- if (Context.getSmsManager() != null) {
+ if (smsManager != null) {
if (command.getType().equals(Command.TYPE_CUSTOM)) {
- Context.getSmsManager().sendMessageSync(destAddress, command.getString(Command.KEY_DATA), true);
+ smsManager.sendMessage(destAddress, command.getString(Command.KEY_DATA), true);
} else if (supportedTextCommands.contains(command.getType()) && textCommandEncoder != null) {
String encodedCommand = (String) textCommandEncoder.encodeCommand(command);
if (encodedCommand != null) {
- Context.getSmsManager().sendMessageSync(destAddress, encodedCommand, true);
+ smsManager.sendMessage(destAddress, encodedCommand, true);
} else {
throw new RuntimeException("Failed to encode command");
}
diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java
index a40756796..69ca0ccc6 100644
--- a/src/main/java/org/traccar/BaseProtocolDecoder.java
+++ b/src/main/java/org/traccar/BaseProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,47 +15,82 @@
*/
package org.traccar;
+import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
-import io.netty.channel.socket.DatagramChannel;
-import io.netty.handler.codec.http.HttpRequestDecoder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.database.CommandsManager;
-import org.traccar.database.ConnectionManager;
-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 jakarta.inject.Inject;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Collection;
import java.util.Date;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
- private static final Logger LOGGER = LoggerFactory.getLogger(BaseProtocolDecoder.class);
-
private static final String PROTOCOL_UNKNOWN = "unknown";
- private final Config config = Context.getConfig();
- private final IdentityManager identityManager = Context.getIdentityManager();
- private final ConnectionManager connectionManager = Context.getConnectionManager();
- private final StatisticsManager statisticsManager;
private final Protocol protocol;
+ private CacheManager cacheManager;
+ private ConnectionManager connectionManager;
+ private StatisticsManager statisticsManager;
+ private MediaManager mediaManager;
+ private CommandsManager commandsManager;
+
public BaseProtocolDecoder(Protocol protocol) {
this.protocol = protocol;
- statisticsManager = Main.getInjector() != null ? Main.getInjector().getInstance(StatisticsManager.class) : null;
+ }
+
+ public CacheManager getCacheManager() {
+ return cacheManager;
+ }
+
+ @Inject
+ public void setCacheManager(CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
+ }
+
+ @Inject
+ public void setConnectionManager(ConnectionManager connectionManager) {
+ this.connectionManager = connectionManager;
+ }
+
+ @Inject
+ public void setStatisticsManager(StatisticsManager statisticsManager) {
+ this.statisticsManager = statisticsManager;
+ }
+
+ @Inject
+ public void setMediaManager(MediaManager mediaManager) {
+ this.mediaManager = mediaManager;
+ }
+
+ @Inject
+ public void setCommandsManager(CommandsManager commandsManager) {
+ this.commandsManager = commandsManager;
+ }
+
+ public CommandsManager getCommandsManager() {
+ return commandsManager;
+ }
+
+ public String writeMediaFile(String uniqueId, ByteBuf buf, String extension) {
+ return mediaManager.writeFile(uniqueId, buf, extension);
}
public String getProtocolName() {
@@ -63,7 +98,7 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
}
public String getServer(Channel channel, char delimiter) {
- String server = config.getString(Keys.PROTOCOL_SERVER.withPrefix(getProtocolName()));
+ String server = getConfig().getString(Keys.PROTOCOL_SERVER.withPrefix(getProtocolName()));
if (server == null && channel != null) {
InetSocketAddress address = (InetSocketAddress) channel.localAddress();
server = address.getAddress().getHostAddress() + ":" + address.getPort();
@@ -72,7 +107,7 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
}
protected double convertSpeed(double value, String defaultUnits) {
- switch (config.getString(getProtocolName() + ".speed", defaultUnits)) {
+ switch (getConfig().getString(getProtocolName() + ".speed", defaultUnits)) {
case "kmh":
return UnitsConverter.knotsFromKph(value);
case "mps":
@@ -91,101 +126,18 @@ 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);
}
return result;
}
- private DeviceSession channelDeviceSession; // connection-based protocols
- private final Map<SocketAddress, DeviceSession> addressDeviceSessions = new HashMap<>(); // connectionless protocols
-
- private long findDeviceId(SocketAddress remoteAddress, String... uniqueIds) {
- if (uniqueIds.length > 0) {
- long deviceId = 0;
- Device device = null;
- try {
- for (String uniqueId : uniqueIds) {
- if (uniqueId != null) {
- device = identityManager.getByUniqueId(uniqueId);
- if (device != null) {
- deviceId = device.getId();
- break;
- }
- }
- }
- } catch (Exception e) {
- LOGGER.warn("Find device error", e);
- }
- if (deviceId == 0 && config.getBoolean(Keys.DATABASE_REGISTER_UNKNOWN)) {
- return identityManager.addUnknownDevice(uniqueIds[0]);
- }
- if (device != null && !device.getDisabled()) {
- return deviceId;
- }
- StringBuilder message = new StringBuilder();
- if (deviceId == 0) {
- message.append("Unknown device -");
- } else {
- message.append("Disabled device -");
- }
- for (String uniqueId : uniqueIds) {
- message.append(" ").append(uniqueId);
- }
- if (remoteAddress != null) {
- message.append(" (").append(((InetSocketAddress) remoteAddress).getHostString()).append(")");
- }
- LOGGER.warn(message.toString());
- }
- return 0;
- }
-
public DeviceSession getDeviceSession(Channel channel, SocketAddress remoteAddress, String... uniqueIds) {
- return getDeviceSession(channel, remoteAddress, false, uniqueIds);
- }
-
- public DeviceSession getDeviceSession(
- Channel channel, SocketAddress remoteAddress, boolean ignoreCache, String... uniqueIds) {
- if (channel != null && BasePipelineFactory.getHandler(channel.pipeline(), HttpRequestDecoder.class) != null
- || ignoreCache || config.getBoolean(Keys.PROTOCOL_IGNORE_SESSIONS_CACHE.withPrefix(getProtocolName()))
- || config.getBoolean(Keys.DECODER_IGNORE_SESSIONS_CACHE)) {
- long deviceId = findDeviceId(remoteAddress, uniqueIds);
- if (deviceId != 0) {
- if (connectionManager != null) {
- connectionManager.addActiveDevice(deviceId, protocol, channel, remoteAddress);
- }
- return new DeviceSession(deviceId);
- } else {
- return null;
- }
- }
- if (channel instanceof DatagramChannel) {
- long deviceId = findDeviceId(remoteAddress, uniqueIds);
- DeviceSession deviceSession = addressDeviceSessions.get(remoteAddress);
- if (deviceSession != null && (deviceSession.getDeviceId() == deviceId || uniqueIds.length == 0)) {
- return deviceSession;
- } else if (deviceId != 0) {
- deviceSession = new DeviceSession(deviceId);
- addressDeviceSessions.put(remoteAddress, deviceSession);
- if (connectionManager != null) {
- connectionManager.addActiveDevice(deviceId, protocol, channel, remoteAddress);
- }
- return deviceSession;
- } else {
- return null;
- }
- } else {
- if (channelDeviceSession == null) {
- long deviceId = findDeviceId(remoteAddress, uniqueIds);
- if (deviceId != 0) {
- channelDeviceSession = new DeviceSession(deviceId);
- if (connectionManager != null) {
- connectionManager.addActiveDevice(deviceId, protocol, channel, remoteAddress);
- }
- }
- }
- return channelDeviceSession;
+ try {
+ return connectionManager.getDeviceSession(protocol, channel, remoteAddress, uniqueIds);
+ } catch (StorageException e) {
+ throw new RuntimeException(e);
}
}
@@ -193,7 +145,7 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
if (position.getDeviceId() != 0) {
position.setOutdated(true);
- Position last = identityManager.getLastPosition(position.getDeviceId());
+ Position last = cacheManager.getPosition(position.getDeviceId());
if (last != null) {
position.setFixTime(last.getFixTime());
position.setValid(last.getValid());
@@ -245,18 +197,15 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
}
protected void sendQueuedCommands(Channel channel, SocketAddress remoteAddress, long deviceId) {
- CommandsManager commandsManager = Context.getCommandsManager();
- if (commandsManager != null) {
- for (Command command : commandsManager.readQueuedCommands(deviceId)) {
- protocol.sendDataCommand(channel, remoteAddress, command);
- }
+ for (Command command : commandsManager.readQueuedCommands(deviceId)) {
+ protocol.sendDataCommand(channel, remoteAddress, command);
}
}
@Override
protected Object handleEmptyMessage(Channel channel, SocketAddress remoteAddress, Object msg) {
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
- if (config.getBoolean(Keys.DATABASE_SAVE_EMPTY) && deviceSession != null) {
+ if (getConfig().getBoolean(Keys.DATABASE_SAVE_EMPTY) && deviceSession != null) {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
getLastLocation(position, null);
diff --git a/src/main/java/org/traccar/BaseProtocolEncoder.java b/src/main/java/org/traccar/BaseProtocolEncoder.java
index b6df07b98..b9ca16838 100644
--- a/src/main/java/org/traccar/BaseProtocolEncoder.java
+++ b/src/main/java/org/traccar/BaseProtocolEncoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -21,7 +21,13 @@ import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.traccar.helper.NetworkUtil;
+import org.traccar.helper.model.AttributeUtil;
import org.traccar.model.Command;
+import org.traccar.model.Device;
+import org.traccar.session.cache.CacheManager;
+
+import jakarta.inject.Inject;
public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter {
@@ -31,22 +37,33 @@ public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter
private final Protocol protocol;
+ private CacheManager cacheManager;
+
public BaseProtocolEncoder(Protocol protocol) {
this.protocol = protocol;
}
+ public CacheManager getCacheManager() {
+ return cacheManager;
+ }
+
+ @Inject
+ public void setCacheManager(CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
+ }
+
public String getProtocolName() {
return protocol != null ? protocol.getName() : PROTOCOL_UNKNOWN;
}
protected String getUniqueId(long deviceId) {
- return Context.getIdentityManager().getById(deviceId).getUniqueId();
+ return cacheManager.getObject(Device.class, deviceId).getUniqueId();
}
protected void initDevicePassword(Command command, String defaultPassword) {
- if (!command.getAttributes().containsKey(Command.KEY_DEVICE_PASSWORD)) {
- String password = Context.getIdentityManager()
- .getDevicePassword(command.getDeviceId(), getProtocolName(), defaultPassword);
+ if (!command.hasAttribute(Command.KEY_DEVICE_PASSWORD)) {
+ String password = AttributeUtil.getDevicePassword(
+ cacheManager, command.getDeviceId(), getProtocolName(), defaultPassword);
command.set(Command.KEY_DEVICE_PASSWORD, password);
}
}
@@ -54,31 +71,30 @@ public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
- NetworkMessage networkMessage = (NetworkMessage) msg;
+ if (msg instanceof NetworkMessage) {
+ NetworkMessage networkMessage = (NetworkMessage) msg;
+ if (networkMessage.getMessage() instanceof Command) {
- if (networkMessage.getMessage() instanceof Command) {
+ Command command = (Command) networkMessage.getMessage();
+ Object encodedCommand = encodeCommand(ctx.channel(), command);
- Command command = (Command) networkMessage.getMessage();
- Object encodedCommand = encodeCommand(ctx.channel(), command);
+ StringBuilder s = new StringBuilder();
+ s.append("[").append(NetworkUtil.session(ctx.channel())).append("] ");
+ s.append("id: ").append(getUniqueId(command.getDeviceId())).append(", ");
+ s.append("command type: ").append(command.getType()).append(" ");
+ if (encodedCommand != null) {
+ s.append("sent");
+ } else {
+ s.append("not sent");
+ }
+ LOGGER.info(s.toString());
- StringBuilder s = new StringBuilder();
- s.append("[").append(ctx.channel().id().asShortText()).append("] ");
- s.append("id: ").append(getUniqueId(command.getDeviceId())).append(", ");
- s.append("command type: ").append(command.getType()).append(" ");
- if (encodedCommand != null) {
- s.append("sent");
- } else {
- s.append("not sent");
- }
- LOGGER.info(s.toString());
-
- ctx.write(new NetworkMessage(encodedCommand, networkMessage.getRemoteAddress()), promise);
-
- } else {
-
- super.write(ctx, msg, promise);
+ ctx.write(new NetworkMessage(encodedCommand, networkMessage.getRemoteAddress()), promise);
+ return;
+ }
}
+ super.write(ctx, msg, promise);
}
protected Object encodeCommand(Channel channel, Command command) {
diff --git a/src/main/java/org/traccar/Context.java b/src/main/java/org/traccar/Context.java
deleted file mode 100644
index aeba9c4c9..000000000
--- a/src/main/java/org/traccar/Context.java
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright 2015 - 2021 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;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fasterxml.jackson.datatype.jsr353.JSR353Module;
-import org.apache.velocity.app.VelocityEngine;
-import org.eclipse.jetty.util.URIUtil;
-import org.traccar.config.Config;
-import org.traccar.config.Keys;
-import org.traccar.database.AttributesManager;
-import org.traccar.database.BaseObjectManager;
-import org.traccar.database.CalendarManager;
-import org.traccar.database.CommandsManager;
-import org.traccar.database.ConnectionManager;
-import org.traccar.database.DataManager;
-import org.traccar.database.DeviceManager;
-import org.traccar.database.DriversManager;
-import org.traccar.database.GeofenceManager;
-import org.traccar.database.GroupsManager;
-import org.traccar.database.IdentityManager;
-import org.traccar.database.LdapProvider;
-import org.traccar.database.MailManager;
-import org.traccar.database.MaintenancesManager;
-import org.traccar.database.MediaManager;
-import org.traccar.database.NotificationManager;
-import org.traccar.database.OrderManager;
-import org.traccar.database.PermissionsManager;
-import org.traccar.database.UsersManager;
-import org.traccar.geocoder.Geocoder;
-import org.traccar.helper.Log;
-import org.traccar.helper.SanitizerModule;
-import org.traccar.model.Attribute;
-import org.traccar.model.BaseModel;
-import org.traccar.model.Calendar;
-import org.traccar.model.Command;
-import org.traccar.model.Device;
-import org.traccar.model.Driver;
-import org.traccar.model.Geofence;
-import org.traccar.model.Group;
-import org.traccar.model.Maintenance;
-import org.traccar.model.Notification;
-import org.traccar.model.Order;
-import org.traccar.model.User;
-import org.traccar.notification.EventForwarder;
-import org.traccar.notification.NotificatorManager;
-import org.traccar.reports.model.TripsConfig;
-import org.traccar.schedule.ScheduleManager;
-import org.traccar.sms.HttpSmsClient;
-import org.traccar.sms.SmsManager;
-import org.traccar.sms.SnsSmsClient;
-import org.traccar.web.WebServer;
-
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.ClientBuilder;
-import javax.ws.rs.ext.ContextResolver;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Properties;
-
-public final class Context {
-
- private Context() {
- }
-
- private static Config config;
-
- public static Config getConfig() {
- return config;
- }
-
- private static ObjectMapper objectMapper;
-
- public static ObjectMapper getObjectMapper() {
- return objectMapper;
- }
-
- private static IdentityManager identityManager;
-
- public static IdentityManager getIdentityManager() {
- return identityManager;
- }
-
- private static DataManager dataManager;
-
- public static DataManager getDataManager() {
- return dataManager;
- }
-
- private static LdapProvider ldapProvider;
-
- public static LdapProvider getLdapProvider() {
- return ldapProvider;
- }
-
- private static MailManager mailManager;
-
- public static MailManager getMailManager() {
- return mailManager;
- }
-
- private static MediaManager mediaManager;
-
- public static MediaManager getMediaManager() {
- return mediaManager;
- }
-
- private static UsersManager usersManager;
-
- public static UsersManager getUsersManager() {
- return usersManager;
- }
-
- private static GroupsManager groupsManager;
-
- public static GroupsManager getGroupsManager() {
- return groupsManager;
- }
-
- private static DeviceManager deviceManager;
-
- public static DeviceManager getDeviceManager() {
- return deviceManager;
- }
-
- private static ConnectionManager connectionManager;
-
- public static ConnectionManager getConnectionManager() {
- return connectionManager;
- }
-
- private static PermissionsManager permissionsManager;
-
- public static PermissionsManager getPermissionsManager() {
- return permissionsManager;
- }
-
- public static Geocoder getGeocoder() {
- return Main.getInjector() != null ? Main.getInjector().getInstance(Geocoder.class) : null;
- }
-
- private static WebServer webServer;
-
- public static WebServer getWebServer() {
- return webServer;
- }
-
- private static ServerManager serverManager;
-
- public static ServerManager getServerManager() {
- return serverManager;
- }
-
- private static ScheduleManager scheduleManager;
-
- public static ScheduleManager getScheduleManager() {
- return scheduleManager;
- }
-
- private static GeofenceManager geofenceManager;
-
- public static GeofenceManager getGeofenceManager() {
- return geofenceManager;
- }
-
- private static CalendarManager calendarManager;
-
- public static CalendarManager getCalendarManager() {
- return calendarManager;
- }
-
- private static NotificationManager notificationManager;
-
- public static NotificationManager getNotificationManager() {
- return notificationManager;
- }
-
- private static NotificatorManager notificatorManager;
-
- public static NotificatorManager getNotificatorManager() {
- return notificatorManager;
- }
-
- private static VelocityEngine velocityEngine;
-
- public static VelocityEngine getVelocityEngine() {
- return velocityEngine;
- }
-
- private static Client client = ClientBuilder.newClient();
-
- public static Client getClient() {
- return client;
- }
-
- private static EventForwarder eventForwarder;
-
- public static EventForwarder getEventForwarder() {
- return eventForwarder;
- }
-
- private static AttributesManager attributesManager;
-
- public static AttributesManager getAttributesManager() {
- return attributesManager;
- }
-
- private static DriversManager driversManager;
-
- public static DriversManager getDriversManager() {
- return driversManager;
- }
-
- private static CommandsManager commandsManager;
-
- public static CommandsManager getCommandsManager() {
- return commandsManager;
- }
-
- private static MaintenancesManager maintenancesManager;
-
- public static MaintenancesManager getMaintenancesManager() {
- return maintenancesManager;
- }
-
- private static OrderManager orderManager;
-
- public static OrderManager getOrderManager() {
- return orderManager;
- }
-
- private static SmsManager smsManager;
-
- public static SmsManager getSmsManager() {
- return smsManager;
- }
-
- private static TripsConfig tripsConfig;
-
- public static TripsConfig getTripsConfig() {
- return tripsConfig;
- }
-
- public static TripsConfig initTripsConfig() {
- return new TripsConfig(
- config.getLong(Keys.REPORT_TRIP_MINIMAL_TRIP_DISTANCE),
- config.getLong(Keys.REPORT_TRIP_MINIMAL_TRIP_DURATION) * 1000,
- config.getLong(Keys.REPORT_TRIP_MINIMAL_PARKING_DURATION) * 1000,
- config.getLong(Keys.REPORT_TRIP_MINIMAL_NO_DATA_DURATION) * 1000,
- config.getBoolean(Keys.REPORT_TRIP_USE_IGNITION),
- config.getBoolean(Keys.EVENT_MOTION_PROCESS_INVALID_POSITIONS),
- config.getDouble(Keys.EVENT_MOTION_SPEED_THRESHOLD));
- }
-
- private static class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
-
- @Override
- public ObjectMapper getContext(Class<?> clazz) {
- return objectMapper;
- }
-
- }
-
- public static void init(String configFile) throws Exception {
-
- try {
- config = new Config(configFile);
- Log.setupLogger(config);
- } catch (Exception e) {
- config = new Config();
- Log.setupDefaultLogger();
- throw e;
- }
-
- objectMapper = new ObjectMapper();
- objectMapper.registerModule(new SanitizerModule());
- objectMapper.registerModule(new JSR353Module());
- objectMapper.setConfig(
- objectMapper.getSerializationConfig().without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS));
-
- client = ClientBuilder.newClient().register(new ObjectMapperContextResolver());
-
- if (config.hasKey(Keys.DATABASE_URL)) {
- dataManager = new DataManager(config);
- }
-
- if (config.hasKey(Keys.LDAP_URL)) {
- ldapProvider = new LdapProvider(config);
- }
-
- mailManager = new MailManager();
-
- mediaManager = new MediaManager(config.getString(Keys.MEDIA_PATH));
-
- if (dataManager != null) {
- usersManager = new UsersManager(dataManager);
- groupsManager = new GroupsManager(dataManager);
- deviceManager = new DeviceManager(dataManager);
- }
-
- identityManager = deviceManager;
-
- if (config.hasKey(Keys.WEB_PORT)) {
- webServer = new WebServer(config);
- }
-
- permissionsManager = new PermissionsManager(dataManager, usersManager);
-
- connectionManager = new ConnectionManager();
-
- tripsConfig = initTripsConfig();
-
- if (config.hasKey(Keys.SMS_HTTP_URL)) {
- smsManager = new HttpSmsClient();
- } else if (config.hasKey(Keys.SMS_AWS_REGION)) {
- smsManager = new SnsSmsClient();
- }
-
- initEventsModule();
-
- serverManager = new ServerManager();
- scheduleManager = new ScheduleManager();
-
- if (config.hasKey(Keys.EVENT_FORWARD_URL)) {
- eventForwarder = new EventForwarder();
- }
-
- attributesManager = new AttributesManager(dataManager);
-
- driversManager = new DriversManager(dataManager);
-
- commandsManager = new CommandsManager(dataManager, config.getBoolean(Keys.COMMANDS_QUEUEING));
-
- orderManager = new OrderManager(dataManager);
-
- }
-
- private static void initEventsModule() {
-
- geofenceManager = new GeofenceManager(dataManager);
- calendarManager = new CalendarManager(dataManager);
- maintenancesManager = new MaintenancesManager(dataManager);
- notificationManager = new NotificationManager(dataManager);
- notificatorManager = new NotificatorManager();
- Properties velocityProperties = new Properties();
- velocityProperties.setProperty("file.resource.loader.path",
- Context.getConfig().getString("templates.rootPath", "templates") + "/");
- velocityProperties.setProperty("runtime.log.logsystem.class",
- "org.apache.velocity.runtime.log.NullLogChute");
-
- String address;
- try {
- address = config.getString(Keys.WEB_ADDRESS, InetAddress.getLocalHost().getHostAddress());
- } catch (UnknownHostException e) {
- address = "localhost";
- }
-
- String webUrl = URIUtil.newURI("http", address, config.getInteger(Keys.WEB_PORT), "", "");
- webUrl = Context.getConfig().getString("web.url", webUrl);
- velocityProperties.setProperty("web.url", webUrl);
-
- velocityEngine = new VelocityEngine();
- velocityEngine.init(velocityProperties);
- }
-
- public static void init(IdentityManager testIdentityManager, MediaManager testMediaManager) {
- config = new Config();
- objectMapper = new ObjectMapper();
- objectMapper.registerModule(new JSR353Module());
- client = ClientBuilder.newClient().register(new ObjectMapperContextResolver());
- identityManager = testIdentityManager;
- mediaManager = testMediaManager;
- }
-
- public static <T extends BaseModel> BaseObjectManager<T> getManager(Class<T> clazz) {
- if (clazz.equals(Device.class)) {
- return (BaseObjectManager<T>) deviceManager;
- } else if (clazz.equals(Group.class)) {
- return (BaseObjectManager<T>) groupsManager;
- } else if (clazz.equals(User.class)) {
- return (BaseObjectManager<T>) usersManager;
- } else if (clazz.equals(Calendar.class)) {
- return (BaseObjectManager<T>) calendarManager;
- } else if (clazz.equals(Attribute.class)) {
- return (BaseObjectManager<T>) attributesManager;
- } else if (clazz.equals(Geofence.class)) {
- return (BaseObjectManager<T>) geofenceManager;
- } else if (clazz.equals(Driver.class)) {
- return (BaseObjectManager<T>) driversManager;
- } else if (clazz.equals(Command.class)) {
- return (BaseObjectManager<T>) commandsManager;
- } else if (clazz.equals(Maintenance.class)) {
- return (BaseObjectManager<T>) maintenancesManager;
- } else if (clazz.equals(Notification.class)) {
- return (BaseObjectManager<T>) notificationManager;
- } else if (clazz.equals(Order.class)) {
- return (BaseObjectManager<T>) orderManager;
- }
- return null;
- }
-
-}
diff --git a/src/main/java/org/traccar/ExtendedObjectDecoder.java b/src/main/java/org/traccar/ExtendedObjectDecoder.java
index 46720da52..cddddcd80 100644
--- a/src/main/java/org/traccar/ExtendedObjectDecoder.java
+++ b/src/main/java/org/traccar/ExtendedObjectDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,18 +21,40 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
+import org.traccar.handler.AcknowledgementHandler;
import org.traccar.helper.DataConverter;
import org.traccar.model.Position;
+import jakarta.inject.Inject;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
+import java.util.List;
public abstract class ExtendedObjectDecoder extends ChannelInboundHandlerAdapter {
+ private Config config;
+
+ public Config getConfig() {
+ return config;
+ }
+
+ @Inject
+ public void setConfig(Config config) {
+ this.config = config;
+ init();
+ }
+
+ /**
+ * Method called when config is initialized.
+ */
+ protected void init() {
+ }
+
private void saveOriginal(Object decodedMessage, Object originalMessage) {
- if (Context.getConfig().getBoolean(Keys.DATABASE_SAVE_ORIGINAL) && decodedMessage instanceof Position) {
+ if (getConfig().getBoolean(Keys.DATABASE_SAVE_ORIGINAL) && decodedMessage instanceof Position) {
Position position = (Position) decodedMessage;
if (originalMessage instanceof ByteBuf) {
ByteBuf buf = (ByteBuf) originalMessage;
@@ -48,6 +70,7 @@ public abstract class ExtendedObjectDecoder extends ChannelInboundHandlerAdapter
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
NetworkMessage networkMessage = (NetworkMessage) msg;
Object originalMessage = networkMessage.getMessage();
+ ctx.writeAndFlush(new AcknowledgementHandler.EventReceived());
try {
Object decodedMessage = decode(ctx.channel(), networkMessage.getRemoteAddress(), originalMessage);
onMessageEvent(ctx.channel(), networkMessage.getRemoteAddress(), originalMessage, decodedMessage);
@@ -56,14 +79,19 @@ public abstract class ExtendedObjectDecoder extends ChannelInboundHandlerAdapter
}
if (decodedMessage != null) {
if (decodedMessage instanceof Collection) {
- for (Object o : (Collection) decodedMessage) {
+ var collection = (Collection) decodedMessage;
+ ctx.writeAndFlush(new AcknowledgementHandler.EventDecoded(collection));
+ for (Object o : collection) {
saveOriginal(o, originalMessage);
ctx.fireChannelRead(o);
}
} else {
+ ctx.writeAndFlush(new AcknowledgementHandler.EventDecoded(List.of(decodedMessage)));
saveOriginal(decodedMessage, originalMessage);
ctx.fireChannelRead(decodedMessage);
}
+ } else {
+ ctx.writeAndFlush(new AcknowledgementHandler.EventDecoded(List.of()));
}
} finally {
ReferenceCountUtil.release(originalMessage);
diff --git a/src/main/java/org/traccar/LifecycleObject.java b/src/main/java/org/traccar/LifecycleObject.java
index 7af21d528..fe0dc698a 100644
--- a/src/main/java/org/traccar/LifecycleObject.java
+++ b/src/main/java/org/traccar/LifecycleObject.java
@@ -17,5 +17,5 @@ package org.traccar;
public interface LifecycleObject {
void start() throws Exception;
- void stop();
+ void stop() throws Exception;
}
diff --git a/src/main/java/org/traccar/Main.java b/src/main/java/org/traccar/Main.java
index 6daf72bb4..e34fbb72a 100644
--- a/src/main/java/org/traccar/Main.java
+++ b/src/main/java/org/traccar/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,13 @@ import com.google.inject.Guice;
import com.google.inject.Injector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.traccar.broadcast.BroadcastService;
+import org.traccar.helper.model.DeviceUtil;
+import org.traccar.schedule.ScheduleManager;
+import org.traccar.storage.DatabaseModule;
+import org.traccar.storage.Storage;
+import org.traccar.web.WebModule;
+import org.traccar.web.WebServer;
import java.io.File;
import java.lang.management.ManagementFactory;
@@ -26,10 +33,10 @@ import java.lang.management.MemoryMXBean;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.RuntimeMXBean;
import java.nio.charset.Charset;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Locale;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
public final class Main {
@@ -110,31 +117,36 @@ public final class Main {
public static void run(String configFile) {
try {
- Context.init(configFile);
- injector = Guice.createInjector(new MainModule());
+ injector = Guice.createInjector(new MainModule(configFile), new DatabaseModule(), new WebModule());
logSystemInfo();
LOGGER.info("Version: " + Main.class.getPackage().getImplementationVersion());
LOGGER.info("Starting server...");
- List<LifecycleObject> services = new LinkedList<>();
- services.add(Context.getServerManager());
- if (Context.getWebServer() != null) {
- services.add(Context.getWebServer());
+ if (injector.getInstance(BroadcastService.class).singleInstance()) {
+ DeviceUtil.resetStatus(injector.getInstance(Storage.class));
}
- services.add(Context.getScheduleManager());
- for (LifecycleObject service : services) {
+ var services = Stream.of(
+ ServerManager.class, WebServer.class, ScheduleManager.class, BroadcastService.class)
+ .map(injector::getInstance)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+
+ for (var service : services) {
service.start();
}
Thread.setDefaultUncaughtExceptionHandler((t, e) -> LOGGER.error("Thread exception", e));
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
- LOGGER.info("Shutting down server...");
-
- Collections.reverse(services);
- for (LifecycleObject service : services) {
- service.stop();
+ LOGGER.info("Stopping server...");
+
+ for (var service : services) {
+ try {
+ service.stop();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
}
}));
} catch (Exception e) {
diff --git a/src/main/java/org/traccar/MainEventHandler.java b/src/main/java/org/traccar/MainEventHandler.java
index a3f6f4105..fb0171d63 100644
--- a/src/main/java/org/traccar/MainEventHandler.java
+++ b/src/main/java/org/traccar/MainEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.traccar;
import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.socket.DatagramChannel;
@@ -23,17 +24,32 @@ import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.database.StatisticsManager;
+import org.traccar.handler.AcknowledgementHandler;
import org.traccar.helper.DateUtil;
+import org.traccar.helper.NetworkUtil;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Device;
import org.traccar.model.Position;
+import org.traccar.session.ConnectionManager;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.storage.Storage;
import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
+@Singleton
+@ChannelHandler.Sharable
public class MainEventHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(MainEventHandler.class);
@@ -41,13 +57,24 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter {
private final Set<String> connectionlessProtocols = new HashSet<>();
private final Set<String> logAttributes = new LinkedHashSet<>();
- public MainEventHandler() {
- String connectionlessProtocolList = Context.getConfig().getString(Keys.STATUS_IGNORE_OFFLINE);
+ private final CacheManager cacheManager;
+ private final Storage storage;
+ private final ConnectionManager connectionManager;
+ private final StatisticsManager statisticsManager;
+
+ @Inject
+ public MainEventHandler(
+ Config config, CacheManager cacheManager, Storage storage, ConnectionManager connectionManager,
+ StatisticsManager statisticsManager) {
+ this.cacheManager = cacheManager;
+ this.storage = storage;
+ this.connectionManager = connectionManager;
+ this.statisticsManager = statisticsManager;
+ String connectionlessProtocolList = config.getString(Keys.STATUS_IGNORE_OFFLINE);
if (connectionlessProtocolList != null) {
connectionlessProtocols.addAll(Arrays.asList(connectionlessProtocolList.split("[, ]")));
}
- logAttributes.addAll(Arrays.asList(
- Context.getConfig().getString(Keys.LOGGER_ATTRIBUTES).split("[, ]")));
+ logAttributes.addAll(Arrays.asList(config.getString(Keys.LOGGER_ATTRIBUTES).split("[, ]")));
}
@Override
@@ -55,17 +82,27 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter {
if (msg instanceof Position) {
Position position = (Position) msg;
+ Device device = cacheManager.getObject(Device.class, position.getDeviceId());
+
try {
- Context.getDeviceManager().updateLatestPosition(position);
+ if (PositionUtil.isLatest(cacheManager, position)) {
+ Device updatedDevice = new Device();
+ updatedDevice.setId(position.getDeviceId());
+ updatedDevice.setPositionId(position.getId());
+ storage.updateObject(updatedDevice, new Request(
+ new Columns.Include("positionId"),
+ new Condition.Equals("id", updatedDevice.getId())));
+
+ cacheManager.updatePosition(position);
+ connectionManager.updatePosition(true, position);
+ }
} catch (StorageException error) {
LOGGER.warn("Failed to update device", error);
}
- String uniqueId = Context.getIdentityManager().getById(position.getDeviceId()).getUniqueId();
-
StringBuilder builder = new StringBuilder();
- builder.append(formatChannel(ctx.channel())).append(" ");
- builder.append("id: ").append(uniqueId);
+ builder.append("[").append(NetworkUtil.session(ctx.channel())).append("] ");
+ builder.append("id: ").append(device.getUniqueId());
for (String attribute : logAttributes) {
switch (attribute) {
case "time":
@@ -108,31 +145,27 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter {
}
LOGGER.info(builder.toString());
- Main.getInjector().getInstance(StatisticsManager.class)
- .registerMessageStored(position.getDeviceId(), position.getProtocol());
- }
- }
+ statisticsManager.registerMessageStored(position.getDeviceId(), position.getProtocol());
- private static String formatChannel(Channel channel) {
- return String.format("[%s]", channel.id().asShortText());
+ ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(position));
+ }
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
if (!(ctx.channel() instanceof DatagramChannel)) {
- LOGGER.info(formatChannel(ctx.channel()) + " connected");
+ LOGGER.info("[{}] connected", NetworkUtil.session(ctx.channel()));
}
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
- LOGGER.info(formatChannel(ctx.channel()) + " disconnected");
+ LOGGER.info("[{}] disconnected", NetworkUtil.session(ctx.channel()));
closeChannel(ctx.channel());
- if (BasePipelineFactory.getHandler(ctx.pipeline(), HttpRequestDecoder.class) == null
- && !connectionlessProtocols.contains(ctx.pipeline().get(BaseProtocolDecoder.class).getProtocolName())) {
- Context.getConnectionManager().removeActiveDevice(ctx.channel());
- }
+ boolean supportsOffline = BasePipelineFactory.getHandler(ctx.pipeline(), HttpRequestDecoder.class) == null
+ && !connectionlessProtocols.contains(ctx.pipeline().get(BaseProtocolDecoder.class).getProtocolName());
+ connectionManager.deviceDisconnected(ctx.channel(), supportsOffline);
}
@Override
@@ -140,14 +173,14 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter {
while (cause.getCause() != null && cause.getCause() != cause) {
cause = cause.getCause();
}
- LOGGER.warn(formatChannel(ctx.channel()) + " error", cause);
+ LOGGER.info("[{}] error", NetworkUtil.session(ctx.channel()), cause);
closeChannel(ctx.channel());
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (evt instanceof IdleStateEvent) {
- LOGGER.info(formatChannel(ctx.channel()) + " timed out");
+ LOGGER.info("[{}] timed out", NetworkUtil.session(ctx.channel()));
closeChannel(ctx.channel());
}
}
diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java
index 842f7e3ce..6ed240d2c 100644
--- a/src/main/java/org/traccar/MainModule.java
+++ b/src/main/java/org/traccar/MainModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,20 +16,36 @@
package org.traccar;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsonp.JSONPModule;
import com.google.inject.AbstractModule;
+import com.google.inject.Injector;
import com.google.inject.Provides;
-import com.google.inject.Singleton;
+import com.google.inject.Scopes;
+import com.google.inject.name.Names;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timer;
+import org.apache.velocity.app.VelocityEngine;
+import org.traccar.broadcast.BroadcastService;
+import org.traccar.broadcast.MulticastBroadcastService;
+import org.traccar.broadcast.RedisBroadcastService;
+import org.traccar.broadcast.NullBroadcastService;
import org.traccar.config.Config;
import org.traccar.config.Keys;
-import org.traccar.database.AttributesManager;
-import org.traccar.database.CalendarManager;
-import org.traccar.database.ConnectionManager;
-import org.traccar.database.DataManager;
-import org.traccar.database.DeviceManager;
-import org.traccar.database.GeofenceManager;
-import org.traccar.database.IdentityManager;
-import org.traccar.database.MaintenancesManager;
+import org.traccar.database.LdapProvider;
+import org.traccar.database.OpenIdProvider;
import org.traccar.database.StatisticsManager;
+import org.traccar.forward.EventForwarder;
+import org.traccar.forward.EventForwarderJson;
+import org.traccar.forward.EventForwarderAmqp;
+import org.traccar.forward.EventForwarderKafka;
+import org.traccar.forward.EventForwarderMqtt;
+import org.traccar.forward.PositionForwarder;
+import org.traccar.forward.PositionForwarderJson;
+import org.traccar.forward.PositionForwarderAmqp;
+import org.traccar.forward.PositionForwarderKafka;
+import org.traccar.forward.PositionForwarderRedis;
+import org.traccar.forward.PositionForwarderUrl;
import org.traccar.geocoder.AddressFormat;
import org.traccar.geocoder.BanGeocoder;
import org.traccar.geocoder.BingMapsGeocoder;
@@ -41,128 +57,146 @@ import org.traccar.geocoder.Geocoder;
import org.traccar.geocoder.GisgraphyGeocoder;
import org.traccar.geocoder.GoogleGeocoder;
import org.traccar.geocoder.HereGeocoder;
+import org.traccar.geocoder.LocationIqGeocoder;
import org.traccar.geocoder.MapQuestGeocoder;
import org.traccar.geocoder.MapTilerGeocoder;
+import org.traccar.geocoder.MapboxGeocoder;
import org.traccar.geocoder.MapmyIndiaGeocoder;
import org.traccar.geocoder.NominatimGeocoder;
import org.traccar.geocoder.OpenCageGeocoder;
import org.traccar.geocoder.PositionStackGeocoder;
+import org.traccar.geocoder.TestGeocoder;
import org.traccar.geocoder.TomTomGeocoder;
-import org.traccar.geocoder.MapboxGeocoder;
import org.traccar.geolocation.GeolocationProvider;
import org.traccar.geolocation.GoogleGeolocationProvider;
import org.traccar.geolocation.MozillaGeolocationProvider;
import org.traccar.geolocation.OpenCellIdGeolocationProvider;
import org.traccar.geolocation.UnwiredGeolocationProvider;
-import org.traccar.handler.ComputedAttributesHandler;
-import org.traccar.handler.CopyAttributesHandler;
-import org.traccar.handler.DefaultDataHandler;
-import org.traccar.handler.DistanceHandler;
-import org.traccar.handler.EngineHoursHandler;
-import org.traccar.handler.FilterHandler;
import org.traccar.handler.GeocoderHandler;
import org.traccar.handler.GeolocationHandler;
-import org.traccar.handler.HemisphereHandler;
-import org.traccar.handler.MotionHandler;
-import org.traccar.handler.RemoteAddressHandler;
import org.traccar.handler.SpeedLimitHandler;
-import org.traccar.handler.TimeHandler;
-import org.traccar.handler.events.AlertEventHandler;
-import org.traccar.handler.events.BehaviorEventHandler;
-import org.traccar.handler.events.CommandResultEventHandler;
-import org.traccar.handler.events.DriverEventHandler;
-import org.traccar.handler.events.FuelDropEventHandler;
-import org.traccar.handler.events.GeofenceEventHandler;
-import org.traccar.handler.events.IgnitionEventHandler;
-import org.traccar.handler.events.MaintenanceEventHandler;
-import org.traccar.handler.events.MotionEventHandler;
-import org.traccar.handler.events.OverspeedEventHandler;
-import org.traccar.reports.model.TripsConfig;
-
-import javax.annotation.Nullable;
-import javax.ws.rs.client.Client;
-import io.netty.util.Timer;
+import org.traccar.helper.ObjectMapperContextResolver;
+import org.traccar.helper.SanitizerModule;
+import org.traccar.helper.WebHelper;
+import org.traccar.mail.LogMailManager;
+import org.traccar.mail.MailManager;
+import org.traccar.mail.SmtpMailManager;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.sms.HttpSmsClient;
+import org.traccar.sms.SmsManager;
+import org.traccar.sms.SnsSmsClient;
import org.traccar.speedlimit.OverpassSpeedLimitProvider;
import org.traccar.speedlimit.SpeedLimitProvider;
+import org.traccar.storage.DatabaseStorage;
+import org.traccar.storage.MemoryStorage;
import org.traccar.storage.Storage;
+import org.traccar.web.WebServer;
+import org.traccar.api.security.LoginService;
+
+import jakarta.annotation.Nullable;
+import jakarta.inject.Singleton;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.http.HttpClient;
+import java.util.Properties;
public class MainModule extends AbstractModule {
- @Provides
- public static ObjectMapper provideObjectMapper() {
- return Context.getObjectMapper();
- }
+ private final String configFile;
- @Provides
- public static Config provideConfig() {
- return Context.getConfig();
- }
-
- @Provides
- public static Storage provideStorage() {
- return Context.getDataManager().getStorage();
- }
-
- @Provides
- public static DataManager provideDataManager() {
- return Context.getDataManager();
- }
-
- @Provides
- public static IdentityManager provideIdentityManager() {
- return Context.getIdentityManager();
+ public MainModule(String configFile) {
+ this.configFile = configFile;
}
- @Provides
- public static ConnectionManager provideConnectionManager() {
- return Context.getConnectionManager();
+ @Override
+ protected void configure() {
+ bindConstant().annotatedWith(Names.named("configFile")).to(configFile);
+ bind(Config.class).asEagerSingleton();
+ bind(Timer.class).to(HashedWheelTimer.class).in(Scopes.SINGLETON);
}
+ @Singleton
@Provides
- public static Client provideClient() {
- return Context.getClient();
+ public static Storage provideStorage(Injector injector, Config config) {
+ if (config.getBoolean(Keys.DATABASE_MEMORY)) {
+ return injector.getInstance(MemoryStorage.class);
+ } else {
+ return injector.getInstance(DatabaseStorage.class);
+ }
}
+ @Singleton
@Provides
- public static TripsConfig provideTripsConfig() {
- return Context.getTripsConfig();
+ public static ObjectMapper provideObjectMapper(Config config) {
+ ObjectMapper objectMapper = new ObjectMapper();
+ if (config.getBoolean(Keys.WEB_SANITIZE)) {
+ objectMapper.registerModule(new SanitizerModule());
+ }
+ objectMapper.registerModule(new JSONPModule());
+ objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ return objectMapper;
}
+ @Singleton
@Provides
- public static DeviceManager provideDeviceManager() {
- return Context.getDeviceManager();
+ public static Client provideClient(ObjectMapperContextResolver objectMapperContextResolver) {
+ return ClientBuilder.newClient().register(objectMapperContextResolver);
}
+ @Singleton
@Provides
- public static GeofenceManager provideGeofenceManager() {
- return Context.getGeofenceManager();
+ public static SmsManager provideSmsManager(Config config, Client client) {
+ if (config.hasKey(Keys.SMS_HTTP_URL)) {
+ return new HttpSmsClient(config, client);
+ } else if (config.hasKey(Keys.SMS_AWS_REGION)) {
+ return new SnsSmsClient(config);
+ }
+ return null;
}
+ @Singleton
@Provides
- public static CalendarManager provideCalendarManager() {
- return Context.getCalendarManager();
+ public static MailManager provideMailManager(Config config, StatisticsManager statisticsManager) {
+ if (config.getBoolean(Keys.MAIL_DEBUG)) {
+ return new LogMailManager();
+ } else {
+ return new SmtpMailManager(config, statisticsManager);
+ }
}
+ @Singleton
@Provides
- public static AttributesManager provideAttributesManager() {
- return Context.getAttributesManager();
+ public static LdapProvider provideLdapProvider(Config config) {
+ if (config.hasKey(Keys.LDAP_URL)) {
+ return new LdapProvider(config);
+ }
+ return null;
}
+ @Singleton
@Provides
- public static MaintenancesManager provideMaintenancesManager() {
- return Context.getMaintenancesManager();
+ public static OpenIdProvider provideOpenIDProvider(
+ Config config, LoginService loginService, ObjectMapper objectMapper
+ ) throws InterruptedException, IOException, URISyntaxException {
+ if (config.hasKey(Keys.OPENID_CLIENT_ID)) {
+ return new OpenIdProvider(config, loginService, HttpClient.newHttpClient(), objectMapper);
+ }
+ return null;
}
- @Singleton
@Provides
- public static StatisticsManager provideStatisticsManager(
- Config config, DataManager dataManager, Client client, ObjectMapper objectMapper) {
- return new StatisticsManager(config, dataManager, client, objectMapper);
+ public static WebServer provideWebServer(Injector injector, Config config) {
+ if (config.hasKey(Keys.WEB_PORT)) {
+ return new WebServer(injector, config);
+ }
+ return null;
}
@Singleton
@Provides
- public static Geocoder provideGeocoder(Config config) {
+ public static Geocoder provideGeocoder(Config config, Client client, StatisticsManager statisticsManager) {
if (config.getBoolean(Keys.GEOCODER_ENABLE)) {
String type = config.getString(Keys.GEOCODER_TYPE, "google");
String url = config.getString(Keys.GEOCODER_URL);
@@ -173,62 +207,88 @@ public class MainModule extends AbstractModule {
AddressFormat addressFormat = formatString != null ? new AddressFormat(formatString) : new AddressFormat();
int cacheSize = config.getInteger(Keys.GEOCODER_CACHE_SIZE);
+ Geocoder geocoder;
switch (type) {
+ case "test":
+ geocoder = new TestGeocoder();
+ break;
case "nominatim":
- return new NominatimGeocoder(url, key, language, cacheSize, addressFormat);
+ geocoder = new NominatimGeocoder(client, url, key, language, cacheSize, addressFormat);
+ break;
+ case "locationiq":
+ geocoder = new LocationIqGeocoder(client, url, key, language, cacheSize, addressFormat);
+ break;
case "gisgraphy":
- return new GisgraphyGeocoder(url, cacheSize, addressFormat);
+ geocoder = new GisgraphyGeocoder(client, url, cacheSize, addressFormat);
+ break;
case "mapquest":
- return new MapQuestGeocoder(url, key, cacheSize, addressFormat);
+ geocoder = new MapQuestGeocoder(client, url, key, cacheSize, addressFormat);
+ break;
case "opencage":
- return new OpenCageGeocoder(url, key, language, cacheSize, addressFormat);
+ geocoder = new OpenCageGeocoder(client, url, key, language, cacheSize, addressFormat);
+ break;
case "bingmaps":
- return new BingMapsGeocoder(url, key, cacheSize, addressFormat);
+ geocoder = new BingMapsGeocoder(client, url, key, cacheSize, addressFormat);
+ break;
case "factual":
- return new FactualGeocoder(url, key, cacheSize, addressFormat);
+ geocoder = new FactualGeocoder(client, url, key, cacheSize, addressFormat);
+ break;
case "geocodefarm":
- return new GeocodeFarmGeocoder(key, language, cacheSize, addressFormat);
+ geocoder = new GeocodeFarmGeocoder(client, key, language, cacheSize, addressFormat);
+ break;
case "geocodexyz":
- return new GeocodeXyzGeocoder(key, cacheSize, addressFormat);
+ geocoder = new GeocodeXyzGeocoder(client, key, cacheSize, addressFormat);
+ break;
case "ban":
- return new BanGeocoder(cacheSize, addressFormat);
+ geocoder = new BanGeocoder(client, cacheSize, addressFormat);
+ break;
case "here":
- return new HereGeocoder(url, id, key, language, cacheSize, addressFormat);
+ geocoder = new HereGeocoder(client, url, id, key, language, cacheSize, addressFormat);
+ break;
case "mapmyindia":
- return new MapmyIndiaGeocoder(url, key, cacheSize, addressFormat);
+ geocoder = new MapmyIndiaGeocoder(client, url, key, cacheSize, addressFormat);
+ break;
case "tomtom":
- return new TomTomGeocoder(url, key, cacheSize, addressFormat);
+ geocoder = new TomTomGeocoder(client, url, key, cacheSize, addressFormat);
+ break;
case "positionstack":
- return new PositionStackGeocoder(key, cacheSize, addressFormat);
+ geocoder = new PositionStackGeocoder(client, key, cacheSize, addressFormat);
+ break;
case "mapbox":
- return new MapboxGeocoder(key, cacheSize, addressFormat);
+ geocoder = new MapboxGeocoder(client, key, cacheSize, addressFormat);
+ break;
case "maptiler":
- return new MapTilerGeocoder(key, cacheSize, addressFormat);
+ geocoder = new MapTilerGeocoder(client, key, cacheSize, addressFormat);
+ break;
case "geoapify":
- return new GeoapifyGeocoder(key, language, cacheSize, addressFormat);
+ geocoder = new GeoapifyGeocoder(client, key, language, cacheSize, addressFormat);
+ break;
default:
- return new GoogleGeocoder(key, language, cacheSize, addressFormat);
+ geocoder = new GoogleGeocoder(client, key, language, cacheSize, addressFormat);
+ break;
}
+ geocoder.setStatisticsManager(statisticsManager);
+ return geocoder;
}
return null;
}
@Singleton
@Provides
- public static GeolocationProvider provideGeolocationProvider(Config config) {
+ public static GeolocationProvider provideGeolocationProvider(Config config, Client client) {
if (config.getBoolean(Keys.GEOLOCATION_ENABLE)) {
String type = config.getString(Keys.GEOLOCATION_TYPE, "mozilla");
String url = config.getString(Keys.GEOLOCATION_URL);
String key = config.getString(Keys.GEOLOCATION_KEY);
switch (type) {
case "google":
- return new GoogleGeolocationProvider(key);
+ return new GoogleGeolocationProvider(client, key);
case "opencellid":
- return new OpenCellIdGeolocationProvider(url, key);
+ return new OpenCellIdGeolocationProvider(client, url, key);
case "unwired":
- return new UnwiredGeolocationProvider(url, key);
+ return new UnwiredGeolocationProvider(client, url, key);
default:
- return new MozillaGeolocationProvider(key);
+ return new MozillaGeolocationProvider(client, key);
}
}
return null;
@@ -236,14 +296,14 @@ public class MainModule extends AbstractModule {
@Singleton
@Provides
- public static SpeedLimitProvider provideSpeedLimitProvider(Config config) {
+ public static SpeedLimitProvider provideSpeedLimitProvider(Config config, Client client) {
if (config.getBoolean(Keys.SPEED_LIMIT_ENABLE)) {
String type = config.getString(Keys.SPEED_LIMIT_TYPE, "overpass");
String url = config.getString(Keys.SPEED_LIMIT_URL);
switch (type) {
case "overpass":
default:
- return new OverpassSpeedLimitProvider(url);
+ return new OverpassSpeedLimitProvider(client, url);
}
}
return null;
@@ -251,53 +311,11 @@ public class MainModule extends AbstractModule {
@Singleton
@Provides
- public static DistanceHandler provideDistanceHandler(Config config, IdentityManager identityManager) {
- return new DistanceHandler(config, identityManager);
- }
-
- @Singleton
- @Provides
- public static FilterHandler provideFilterHandler(Config config) {
- if (config.getBoolean(Keys.FILTER_ENABLE)) {
- return new FilterHandler(config);
- }
- return null;
- }
-
- @Singleton
- @Provides
- public static HemisphereHandler provideHemisphereHandler(Config config) {
- if (config.hasKey(Keys.LOCATION_LATITUDE_HEMISPHERE) || config.hasKey(Keys.LOCATION_LONGITUDE_HEMISPHERE)) {
- return new HemisphereHandler(config);
- }
- return null;
- }
-
- @Singleton
- @Provides
- public static RemoteAddressHandler provideRemoteAddressHandler(Config config) {
- if (config.getBoolean(Keys.PROCESSING_REMOTE_ADDRESS_ENABLE)) {
- return new RemoteAddressHandler();
- }
- return null;
- }
-
- @Singleton
- @Provides
- public static WebDataHandler provideWebDataHandler(
- Config config, IdentityManager identityManager, ObjectMapper objectMapper, Client client) {
- if (config.hasKey(Keys.FORWARD_URL)) {
- return new WebDataHandler(config, identityManager, objectMapper, client);
- }
- return null;
- }
-
- @Singleton
- @Provides
public static GeolocationHandler provideGeolocationHandler(
- Config config, @Nullable GeolocationProvider geolocationProvider, StatisticsManager statisticsManager) {
+ Config config, @Nullable GeolocationProvider geolocationProvider, CacheManager cacheManager,
+ StatisticsManager statisticsManager) {
if (geolocationProvider != null) {
- return new GeolocationHandler(config, geolocationProvider, statisticsManager);
+ return new GeolocationHandler(config, geolocationProvider, cacheManager, statisticsManager);
}
return null;
}
@@ -305,9 +323,9 @@ public class MainModule extends AbstractModule {
@Singleton
@Provides
public static GeocoderHandler provideGeocoderHandler(
- Config config, @Nullable Geocoder geocoder, IdentityManager identityManager) {
+ Config config, @Nullable Geocoder geocoder, CacheManager cacheManager) {
if (geocoder != null) {
- return new GeocoderHandler(config, geocoder, identityManager);
+ return new GeocoderHandler(config, geocoder, cacheManager);
}
return null;
}
@@ -323,130 +341,72 @@ public class MainModule extends AbstractModule {
@Singleton
@Provides
- public static MotionHandler provideMotionHandler(TripsConfig tripsConfig) {
- return new MotionHandler(tripsConfig.getSpeedThreshold());
- }
-
- @Singleton
- @Provides
- public static EngineHoursHandler provideEngineHoursHandler(Config config, IdentityManager identityManager) {
- if (config.getBoolean(Keys.PROCESSING_ENGINE_HOURS_ENABLE)) {
- return new EngineHoursHandler(identityManager);
- }
- return null;
- }
-
- @Singleton
- @Provides
- public static CopyAttributesHandler provideCopyAttributesHandler(Config config, IdentityManager identityManager) {
- if (config.getBoolean(Keys.PROCESSING_COPY_ATTRIBUTES_ENABLE)) {
- return new CopyAttributesHandler(identityManager);
- }
- return null;
- }
-
- @Singleton
- @Provides
- public static ComputedAttributesHandler provideComputedAttributesHandler(
- Config config, IdentityManager identityManager, AttributesManager attributesManager) {
- if (config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_ENABLE)) {
- return new ComputedAttributesHandler(config, identityManager, attributesManager);
+ public static BroadcastService provideBroadcastService(
+ Config config, ObjectMapper objectMapper) throws IOException {
+ if (config.hasKey(Keys.BROADCAST_TYPE)) {
+ switch (config.getString(Keys.BROADCAST_TYPE)) {
+ case "multicast":
+ return new MulticastBroadcastService(config, objectMapper);
+ case "redis":
+ return new RedisBroadcastService(config, objectMapper);
+ default:
+ break;
+ }
}
- return null;
+ return new NullBroadcastService();
}
@Singleton
@Provides
- public static TimeHandler provideTimeHandler(Config config) {
- if (config.hasKey(Keys.TIME_OVERRIDE)) {
- return new TimeHandler(config);
+ public static EventForwarder provideEventForwarder(Config config, Client client, ObjectMapper objectMapper) {
+ if (config.hasKey(Keys.EVENT_FORWARD_URL)) {
+ String forwardType = config.getString(Keys.EVENT_FORWARD_TYPE);
+ switch (forwardType) {
+ case "amqp":
+ return new EventForwarderAmqp(config, objectMapper);
+ case "kafka":
+ return new EventForwarderKafka(config, objectMapper);
+ case "mqtt":
+ return new EventForwarderMqtt(config, objectMapper);
+ case "json":
+ default:
+ return new EventForwarderJson(config, client);
+ }
}
return null;
}
@Singleton
@Provides
- public static DefaultDataHandler provideDefaultDataHandler(@Nullable DataManager dataManager) {
- if (dataManager != null) {
- return new DefaultDataHandler(dataManager);
+ public static PositionForwarder providePositionForwarder(Config config, Client client, ObjectMapper objectMapper) {
+ if (config.hasKey(Keys.FORWARD_URL)) {
+ switch (config.getString(Keys.FORWARD_TYPE)) {
+ case "json":
+ return new PositionForwarderJson(config, client, objectMapper);
+ case "amqp":
+ return new PositionForwarderAmqp(config, objectMapper);
+ case "kafka":
+ return new PositionForwarderKafka(config, objectMapper);
+ case "redis":
+ return new PositionForwarderRedis(config, objectMapper);
+ case "url":
+ default:
+ return new PositionForwarderUrl(config, client, objectMapper);
+ }
}
return null;
}
@Singleton
@Provides
- public static CommandResultEventHandler provideCommandResultEventHandler() {
- return new CommandResultEventHandler();
- }
+ public static VelocityEngine provideVelocityEngine(Config config) {
+ Properties properties = new Properties();
+ properties.setProperty("resource.loader.file.path", config.getString(Keys.TEMPLATES_ROOT) + "/");
+ properties.setProperty("web.url", WebHelper.retrieveWebUrl(config));
- @Singleton
- @Provides
- public static OverspeedEventHandler provideOverspeedEventHandler(
- Config config, DeviceManager deviceManager, GeofenceManager geofenceManager) {
- return new OverspeedEventHandler(config, deviceManager, geofenceManager);
- }
-
- @Singleton
- @Provides
- public static BehaviorEventHandler provideBehaviorEventHandler(Config config, IdentityManager identityManager) {
- return new BehaviorEventHandler(config, identityManager);
- }
-
- @Singleton
- @Provides
- public static FuelDropEventHandler provideFuelDropEventHandler(IdentityManager identityManager) {
- return new FuelDropEventHandler(identityManager);
- }
-
- @Singleton
- @Provides
- public static MotionEventHandler provideMotionEventHandler(
- IdentityManager identityManager, DeviceManager deviceManager, TripsConfig tripsConfig) {
- return new MotionEventHandler(identityManager, deviceManager, tripsConfig);
- }
-
- @Singleton
- @Provides
- public static GeofenceEventHandler provideGeofenceEventHandler(
- IdentityManager identityManager, GeofenceManager geofenceManager, CalendarManager calendarManager,
- ConnectionManager connectionManager) {
- return new GeofenceEventHandler(identityManager, geofenceManager, calendarManager, connectionManager);
- }
-
- @Singleton
- @Provides
- public static AlertEventHandler provideAlertEventHandler(Config config, IdentityManager identityManager) {
- return new AlertEventHandler(config, identityManager);
- }
-
- @Singleton
- @Provides
- public static IgnitionEventHandler provideIgnitionEventHandler(IdentityManager identityManager) {
- return new IgnitionEventHandler(identityManager);
- }
-
- @Singleton
- @Provides
- public static MaintenanceEventHandler provideMaintenanceEventHandler(
- IdentityManager identityManager, MaintenancesManager maintenancesManager) {
- return new MaintenanceEventHandler(identityManager, maintenancesManager);
- }
-
- @Singleton
- @Provides
- public static DriverEventHandler provideDriverEventHandler(IdentityManager identityManager) {
- return new DriverEventHandler(identityManager);
- }
-
- @Singleton
- @Provides
- public static Timer provideTimer() {
- return GlobalTimer.getTimer();
- }
-
- @Override
- protected void configure() {
- binder().requireExplicitBindings();
+ VelocityEngine velocityEngine = new VelocityEngine();
+ velocityEngine.init(properties);
+ return velocityEngine;
}
}
diff --git a/src/main/java/org/traccar/PositionForwardingHandler.java b/src/main/java/org/traccar/PositionForwardingHandler.java
new file mode 100644
index 000000000..a79b01367
--- /dev/null
+++ b/src/main/java/org/traccar/PositionForwardingHandler.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2015 - 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;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.util.Timeout;
+import io.netty.util.Timer;
+import io.netty.util.TimerTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.forward.PositionData;
+import org.traccar.forward.PositionForwarder;
+import org.traccar.forward.ResultHandler;
+import org.traccar.model.Device;
+import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+
+import jakarta.annotation.Nullable;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@Singleton
+@ChannelHandler.Sharable
+public class PositionForwardingHandler extends BaseDataHandler {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PositionForwardingHandler.class);
+
+ private final CacheManager cacheManager;
+ private final Timer timer;
+
+ private final PositionForwarder positionForwarder;
+
+ private final boolean retryEnabled;
+ private final int retryDelay;
+ private final int retryCount;
+ private final int retryLimit;
+
+ private final AtomicInteger deliveryPending;
+
+ @Inject
+ public PositionForwardingHandler(
+ Config config, CacheManager cacheManager, Timer timer, @Nullable PositionForwarder positionForwarder) {
+
+ this.cacheManager = cacheManager;
+ this.timer = timer;
+ this.positionForwarder = positionForwarder;
+
+ this.retryEnabled = config.getBoolean(Keys.FORWARD_RETRY_ENABLE);
+ this.retryDelay = config.getInteger(Keys.FORWARD_RETRY_DELAY);
+ this.retryCount = config.getInteger(Keys.FORWARD_RETRY_COUNT);
+ this.retryLimit = config.getInteger(Keys.FORWARD_RETRY_LIMIT);
+
+ this.deliveryPending = new AtomicInteger();
+ }
+
+ class AsyncRequestAndCallback implements ResultHandler, TimerTask {
+
+ private final PositionData positionData;
+
+ private int retries = 0;
+
+ AsyncRequestAndCallback(PositionData positionData) {
+ this.positionData = positionData;
+ deliveryPending.incrementAndGet();
+ }
+
+ private void send() {
+ positionForwarder.forward(positionData, this);
+ }
+
+ private void retry(Throwable throwable) {
+ boolean scheduled = false;
+ try {
+ if (retryEnabled && deliveryPending.get() <= retryLimit && retries < retryCount) {
+ schedule();
+ scheduled = true;
+ }
+ } finally {
+ int pending = scheduled ? deliveryPending.get() : deliveryPending.decrementAndGet();
+ LOGGER.warn("Position forwarding failed: " + pending + " pending", throwable);
+ }
+ }
+
+ private void schedule() {
+ timer.newTimeout(this, retryDelay * (long) Math.pow(2, retries++), TimeUnit.MILLISECONDS);
+ }
+
+ @Override
+ public void onResult(boolean success, Throwable throwable) {
+ if (success) {
+ deliveryPending.decrementAndGet();
+ } else {
+ retry(throwable);
+ }
+ }
+
+ @Override
+ public void run(Timeout timeout) {
+ boolean sent = false;
+ try {
+ if (!timeout.isCancelled()) {
+ send();
+ sent = true;
+ }
+ } finally {
+ if (!sent) {
+ deliveryPending.decrementAndGet();
+ }
+ }
+ }
+ }
+
+ @Override
+ protected Position handlePosition(Position position) {
+ if (positionForwarder != null) {
+ PositionData positionData = new PositionData();
+ positionData.setPosition(position);
+ positionData.setDevice(cacheManager.getObject(Device.class, position.getDeviceId()));
+ new AsyncRequestAndCallback(positionData).send();
+ }
+ return position;
+ }
+
+}
diff --git a/src/main/java/org/traccar/ServerManager.java b/src/main/java/org/traccar/ServerManager.java
index 15faf9f2b..e91be50a2 100644
--- a/src/main/java/org/traccar/ServerManager.java
+++ b/src/main/java/org/traccar/ServerManager.java
@@ -15,20 +15,28 @@
*/
package org.traccar;
+import com.google.inject.Injector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.helper.ClassScanner;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
import java.io.IOException;
import java.net.BindException;
import java.net.ConnectException;
import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+@Singleton
public class ServerManager implements LifecycleObject {
private static final Logger LOGGER = LoggerFactory.getLogger(ServerManager.class);
@@ -36,12 +44,21 @@ public class ServerManager implements LifecycleObject {
private final List<TrackerConnector> connectorList = new LinkedList<>();
private final Map<String, BaseProtocol> protocolList = new ConcurrentHashMap<>();
- public ServerManager() throws IOException, URISyntaxException, ReflectiveOperationException {
+ @Inject
+ public ServerManager(
+ Injector injector, Config config) throws IOException, URISyntaxException, ReflectiveOperationException {
+ Set<String> enabledProtocols = null;
+ if (config.hasKey(Keys.PROTOCOLS_ENABLE)) {
+ enabledProtocols = new HashSet<>(Arrays.asList(config.getString(Keys.PROTOCOLS_ENABLE).split("[, ]")));
+ }
for (Class<?> protocolClass : ClassScanner.findSubclasses(BaseProtocol.class, "org.traccar.protocol")) {
- if (Context.getConfig().hasKey(Keys.PROTOCOL_PORT.withPrefix(BaseProtocol.nameFromClass(protocolClass)))) {
- BaseProtocol protocol = (BaseProtocol) protocolClass.getDeclaredConstructor().newInstance();
- connectorList.addAll(protocol.getConnectorList());
- protocolList.put(protocol.getName(), protocol);
+ String protocolName = BaseProtocol.nameFromClass(protocolClass);
+ if (enabledProtocols == null || enabledProtocols.contains(protocolName)) {
+ if (config.hasKey(Keys.PROTOCOL_PORT.withPrefix(protocolName))) {
+ BaseProtocol protocol = (BaseProtocol) injector.getInstance(protocolClass);
+ connectorList.addAll(protocol.getConnectorList());
+ protocolList.put(protocol.getName(), protocol);
+ }
}
}
}
@@ -64,11 +81,14 @@ public class ServerManager implements LifecycleObject {
}
@Override
- public void stop() {
- for (TrackerConnector connector: connectorList) {
- connector.stop();
+ public void stop() throws Exception {
+ try {
+ for (TrackerConnector connector : connectorList) {
+ connector.stop();
+ }
+ } finally {
+ GlobalTimer.release();
}
- GlobalTimer.release();
}
}
diff --git a/src/main/java/org/traccar/TrackerClient.java b/src/main/java/org/traccar/TrackerClient.java
index dda02f909..2d6b227da 100644
--- a/src/main/java/org/traccar/TrackerClient.java
+++ b/src/main/java/org/traccar/TrackerClient.java
@@ -23,6 +23,7 @@ import io.netty.handler.ssl.SslHandler;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.GlobalEventExecutor;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import javax.net.ssl.SSLContext;
@@ -52,15 +53,14 @@ public abstract class TrackerClient implements TrackerConnector {
return secure;
}
- public TrackerClient(String protocol) {
+ public TrackerClient(Config config, String protocol) {
+ secure = config.getBoolean(Keys.PROTOCOL_SSL.withPrefix(protocol));
+ interval = config.getLong(Keys.PROTOCOL_INTERVAL.withPrefix(protocol));
+ address = config.getString(Keys.PROTOCOL_ADDRESS.withPrefix(protocol));
+ port = config.getInteger(Keys.PROTOCOL_PORT.withPrefix(protocol), secure ? 443 : 80);
+ devices = config.getString(Keys.PROTOCOL_DEVICES.withPrefix(protocol)).split("[, ]");
- secure = Context.getConfig().getBoolean(Keys.PROTOCOL_SSL.withPrefix(protocol));
- interval = Context.getConfig().getLong(Keys.PROTOCOL_INTERVAL.withPrefix(protocol));
- address = Context.getConfig().getString(Keys.PROTOCOL_ADDRESS.withPrefix(protocol));
- port = Context.getConfig().getInteger(Keys.PROTOCOL_PORT.withPrefix(protocol), secure ? 443 : 80);
- devices = Context.getConfig().getString(Keys.PROTOCOL_DEVICES.withPrefix(protocol)).split("[, ]");
-
- BasePipelineFactory pipelineFactory = new BasePipelineFactory(this, protocol) {
+ BasePipelineFactory pipelineFactory = new BasePipelineFactory(this, config, protocol) {
@Override
protected void addTransportHandlers(PipelineBuilder pipeline) {
try {
@@ -77,7 +77,7 @@ public abstract class TrackerClient implements TrackerConnector {
@Override
protected void addProtocolHandlers(PipelineBuilder pipeline) {
try {
- TrackerClient.this.addProtocolHandlers(pipeline);
+ TrackerClient.this.addProtocolHandlers(pipeline, config);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -90,7 +90,7 @@ public abstract class TrackerClient implements TrackerConnector {
.handler(pipelineFactory);
}
- protected abstract void addProtocolHandlers(PipelineBuilder pipeline) throws Exception;
+ protected abstract void addProtocolHandlers(PipelineBuilder pipeline, Config config) throws Exception;
public String[] getDevices() {
return devices;
diff --git a/src/main/java/org/traccar/TrackerServer.java b/src/main/java/org/traccar/TrackerServer.java
index 8e2fce616..0e0837cfb 100644
--- a/src/main/java/org/traccar/TrackerServer.java
+++ b/src/main/java/org/traccar/TrackerServer.java
@@ -25,6 +25,7 @@ import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.concurrent.GlobalEventExecutor;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import javax.net.ssl.SSLContext;
@@ -54,14 +55,12 @@ public abstract class TrackerServer implements TrackerConnector {
return secure;
}
- public TrackerServer(boolean datagram, String protocol) {
- this.datagram = datagram;
-
- secure = Context.getConfig().getBoolean(Keys.PROTOCOL_SSL.withPrefix(protocol));
- address = Context.getConfig().getString(Keys.PROTOCOL_ADDRESS.withPrefix(protocol));
- port = Context.getConfig().getInteger(Keys.PROTOCOL_PORT.withPrefix(protocol));
+ public TrackerServer(Config config, String protocol, boolean datagram) {
+ secure = config.getBoolean(Keys.PROTOCOL_SSL.withPrefix(protocol));
+ address = config.getString(Keys.PROTOCOL_ADDRESS.withPrefix(protocol));
+ port = config.getInteger(Keys.PROTOCOL_PORT.withPrefix(protocol));
- BasePipelineFactory pipelineFactory = new BasePipelineFactory(this, protocol) {
+ BasePipelineFactory pipelineFactory = new BasePipelineFactory(this, config, protocol) {
@Override
protected void addTransportHandlers(PipelineBuilder pipeline) {
try {
@@ -76,28 +75,25 @@ public abstract class TrackerServer implements TrackerConnector {
@Override
protected void addProtocolHandlers(PipelineBuilder pipeline) {
- TrackerServer.this.addProtocolHandlers(pipeline);
+ TrackerServer.this.addProtocolHandlers(pipeline, config);
}
};
+ this.datagram = datagram;
if (datagram) {
-
bootstrap = new Bootstrap()
.group(EventLoopGroupFactory.getWorkerGroup())
.channel(NioDatagramChannel.class)
.handler(pipelineFactory);
-
} else {
-
bootstrap = new ServerBootstrap()
.group(EventLoopGroupFactory.getBossGroup(), EventLoopGroupFactory.getWorkerGroup())
.channel(NioServerSocketChannel.class)
.childHandler(pipelineFactory);
-
}
}
- protected abstract void addProtocolHandlers(PipelineBuilder pipeline);
+ protected abstract void addProtocolHandlers(PipelineBuilder pipeline, Config config);
public int getPort() {
return port;
diff --git a/src/main/java/org/traccar/WebDataHandler.java b/src/main/java/org/traccar/WebDataHandler.java
deleted file mode 100644
index 678096d34..000000000
--- a/src/main/java/org/traccar/WebDataHandler.java
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Copyright 2015 - 2020 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;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import io.netty.channel.ChannelHandler;
-import io.netty.util.Timer;
-import io.netty.util.Timeout;
-import io.netty.util.TimerTask;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.traccar.config.Config;
-import org.traccar.config.Keys;
-import org.traccar.database.IdentityManager;
-import org.traccar.helper.Checksum;
-import org.traccar.model.Device;
-import org.traccar.model.Position;
-import org.traccar.model.Group;
-
-import javax.inject.Inject;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.Invocation;
-import javax.ws.rs.client.InvocationCallback;
-import java.util.HashMap;
-import java.util.Map;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.util.Calendar;
-import java.util.Formatter;
-import java.util.Locale;
-import java.util.TimeZone;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-@ChannelHandler.Sharable
-public class WebDataHandler extends BaseDataHandler {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(WebDataHandler.class);
-
- private static final String KEY_POSITION = "position";
- private static final String KEY_DEVICE = "device";
-
- private final IdentityManager identityManager;
- private final ObjectMapper objectMapper;
- private final Client client;
-
- private final String url;
- private final String header;
- private final boolean json;
- private final boolean urlVariables;
-
- private final boolean retryEnabled;
- private final int retryDelay;
- private final int retryCount;
- private final int retryLimit;
-
- private final AtomicInteger deliveryPending;
-
- @Inject
- public WebDataHandler(
- Config config, IdentityManager identityManager, ObjectMapper objectMapper, Client client) {
-
- this.identityManager = identityManager;
- this.objectMapper = objectMapper;
- this.client = client;
- this.url = config.getString(Keys.FORWARD_URL);
- this.header = config.getString(Keys.FORWARD_HEADER);
- this.json = config.getBoolean(Keys.FORWARD_JSON);
- this.urlVariables = config.getBoolean(Keys.FORWARD_URL_VARIABLES);
-
- this.retryEnabled = config.getBoolean(Keys.FORWARD_RETRY_ENABLE);
- this.retryDelay = config.getInteger(Keys.FORWARD_RETRY_DELAY, 100);
- this.retryCount = config.getInteger(Keys.FORWARD_RETRY_COUNT, 10);
- this.retryLimit = config.getInteger(Keys.FORWARD_RETRY_LIMIT, 100);
-
- this.deliveryPending = new AtomicInteger(0);
- }
-
- private static String formatSentence(Position position) {
-
- StringBuilder s = new StringBuilder("$GPRMC,");
-
- try (Formatter f = new Formatter(s, Locale.ENGLISH)) {
-
- Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.ENGLISH);
- calendar.setTimeInMillis(position.getFixTime().getTime());
-
- f.format("%1$tH%1$tM%1$tS.%1$tL,A,", calendar);
-
- double lat = position.getLatitude();
- double lon = position.getLongitude();
-
- f.format("%02d%07.4f,%c,", (int) Math.abs(lat), Math.abs(lat) % 1 * 60, lat < 0 ? 'S' : 'N');
- f.format("%03d%07.4f,%c,", (int) Math.abs(lon), Math.abs(lon) % 1 * 60, lon < 0 ? 'W' : 'E');
-
- f.format("%.2f,%.2f,", position.getSpeed(), position.getCourse());
- f.format("%1$td%1$tm%1$ty,,", calendar);
- }
-
- s.append(Checksum.nmea(s.substring(1)));
-
- return s.toString();
- }
-
- private String calculateStatus(Position position) {
- if (position.getAttributes().containsKey(Position.KEY_ALARM)) {
- return "0xF841"; // STATUS_PANIC_ON
- } else if (position.getSpeed() < 1.0) {
- return "0xF020"; // STATUS_LOCATION
- } else {
- return "0xF11C"; // STATUS_MOTION_MOVING
- }
- }
-
- public String formatRequest(Position position) throws UnsupportedEncodingException, JsonProcessingException {
-
- Device device = identityManager.getById(position.getDeviceId());
-
- String request = url
- .replace("{name}", URLEncoder.encode(device.getName(), StandardCharsets.UTF_8.name()))
- .replace("{uniqueId}", device.getUniqueId())
- .replace("{status}", device.getStatus())
- .replace("{deviceId}", String.valueOf(position.getDeviceId()))
- .replace("{protocol}", String.valueOf(position.getProtocol()))
- .replace("{deviceTime}", String.valueOf(position.getDeviceTime().getTime()))
- .replace("{fixTime}", String.valueOf(position.getFixTime().getTime()))
- .replace("{valid}", String.valueOf(position.getValid()))
- .replace("{latitude}", String.valueOf(position.getLatitude()))
- .replace("{longitude}", String.valueOf(position.getLongitude()))
- .replace("{altitude}", String.valueOf(position.getAltitude()))
- .replace("{speed}", String.valueOf(position.getSpeed()))
- .replace("{course}", String.valueOf(position.getCourse()))
- .replace("{accuracy}", String.valueOf(position.getAccuracy()))
- .replace("{statusCode}", calculateStatus(position));
-
- if (position.getAddress() != null) {
- request = request.replace(
- "{address}", URLEncoder.encode(position.getAddress(), StandardCharsets.UTF_8.name()));
- }
-
- if (request.contains("{attributes}")) {
- String attributes = objectMapper.writeValueAsString(position.getAttributes());
- request = request.replace(
- "{attributes}", URLEncoder.encode(attributes, StandardCharsets.UTF_8.name()));
- }
-
- if (request.contains("{gprmc}")) {
- request = request.replace("{gprmc}", formatSentence(position));
- }
-
- if (request.contains("{group}")) {
- String deviceGroupName = "";
- if (device.getGroupId() != 0) {
- Group group = Context.getGroupsManager().getById(device.getGroupId());
- if (group != null) {
- deviceGroupName = group.getName();
- }
- }
-
- request = request.replace("{group}", URLEncoder.encode(deviceGroupName, StandardCharsets.UTF_8.name()));
- }
-
- return request;
- }
-
- class AsyncRequestAndCallback implements InvocationCallback<Response>, TimerTask {
-
- private int retries = 0;
- private Map<String, Object> payload;
- private final Invocation.Builder requestBuilder;
- private MediaType mediaType = MediaType.APPLICATION_JSON_TYPE;
-
- AsyncRequestAndCallback(Position position) {
-
- String formattedUrl;
- try {
- formattedUrl = json && !urlVariables ? url : formatRequest(position);
- } catch (UnsupportedEncodingException | JsonProcessingException e) {
- throw new RuntimeException("Forwarding formatting error", e);
- }
-
- requestBuilder = client.target(formattedUrl).request();
- if (header != null && !header.isEmpty()) {
- for (String line: header.split("\\r?\\n")) {
- String[] values = line.split(":", 2);
- String headerName = values[0].trim();
- String headerValue = values[1].trim();
- if (headerName.equals(HttpHeaders.CONTENT_TYPE)) {
- mediaType = MediaType.valueOf(headerValue);
- } else {
- requestBuilder.header(headerName, headerValue);
- }
- }
- }
-
- if (json) {
- payload = prepareJsonPayload(position);
- }
-
- deliveryPending.incrementAndGet();
- }
-
- private void send() {
- LOGGER.debug("Position forwarding initiated");
- if (json) {
- try {
- Entity<String> entity = Entity.entity(objectMapper.writeValueAsString(payload), mediaType);
- requestBuilder.async().post(entity, this);
- } catch (JsonProcessingException e) {
- throw new RuntimeException("Failed to serialize location to json", e);
- }
- } else {
- requestBuilder.async().get(this);
- }
- }
-
- private void retry(Throwable throwable) {
- boolean scheduled = false;
- try {
- if (retryEnabled && deliveryPending.get() <= retryLimit && retries < retryCount) {
- schedule();
- scheduled = true;
- }
- } finally {
- int pending = scheduled ? deliveryPending.get() : deliveryPending.decrementAndGet();
- LOGGER.warn("Position forwarding failed: " + pending + " pending", throwable);
- }
- }
-
- private void schedule() {
- Main.getInjector().getInstance(Timer.class).newTimeout(
- this, retryDelay * (long) Math.pow(2, retries++), TimeUnit.MILLISECONDS);
- }
-
- @Override
- public void completed(Response response) {
- if (response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL) {
- deliveryPending.decrementAndGet();
- LOGGER.debug("Position forwarding succeeded");
- } else {
- retry(new RuntimeException("Status code 2xx expected"));
- }
- }
-
- @Override
- public void failed(Throwable throwable) {
- retry(throwable);
- }
-
- @Override
- public void run(Timeout timeout) {
- boolean sent = false;
- try {
- if (!timeout.isCancelled()) {
- send();
- sent = true;
- }
- } finally {
- if (!sent) {
- deliveryPending.decrementAndGet();
- }
- }
- }
-
- }
-
- @Override
- protected Position handlePosition(Position position) {
-
- AsyncRequestAndCallback request = new AsyncRequestAndCallback(position);
- request.send();
-
- return position;
- }
-
- private Map<String, Object> prepareJsonPayload(Position position) {
-
- Map<String, Object> data = new HashMap<>();
- Device device = identityManager.getById(position.getDeviceId());
-
- data.put(KEY_POSITION, position);
-
- if (device != null) {
- data.put(KEY_DEVICE, device);
- }
-
- return data;
- }
-
-}
diff --git a/src/main/java/org/traccar/api/AsyncSocket.java b/src/main/java/org/traccar/api/AsyncSocket.java
index b1853822d..5fc4b4412 100644
--- a/src/main/java/org/traccar/api/AsyncSocket.java
+++ b/src/main/java/org/traccar/api/AsyncSocket.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -16,15 +16,18 @@
package org.traccar.api;
import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.database.ConnectionManager;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.session.ConnectionManager;
import org.traccar.model.Device;
import org.traccar.model.Event;
import org.traccar.model.Position;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
import java.util.Collection;
import java.util.Collections;
@@ -39,9 +42,15 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U
private static final String KEY_POSITIONS = "positions";
private static final String KEY_EVENTS = "events";
+ private final ObjectMapper objectMapper;
+ private final ConnectionManager connectionManager;
+ private final Storage storage;
private final long userId;
- public AsyncSocket(long userId) {
+ public AsyncSocket(ObjectMapper objectMapper, ConnectionManager connectionManager, Storage storage, long userId) {
+ this.objectMapper = objectMapper;
+ this.connectionManager = connectionManager;
+ this.storage = storage;
this.userId = userId;
}
@@ -49,18 +58,21 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U
public void onWebSocketConnect(Session session) {
super.onWebSocketConnect(session);
- Map<String, Collection<?>> data = new HashMap<>();
- data.put(KEY_POSITIONS, Context.getDeviceManager().getInitialState(userId));
- sendData(data);
-
- Context.getConnectionManager().addListener(userId, this);
+ try {
+ Map<String, Collection<?>> data = new HashMap<>();
+ data.put(KEY_POSITIONS, PositionUtil.getLatestPositions(storage, userId));
+ sendData(data);
+ connectionManager.addListener(userId, this);
+ } catch (StorageException e) {
+ throw new RuntimeException(e);
+ }
}
@Override
public void onWebSocketClose(int statusCode, String reason) {
super.onWebSocketClose(statusCode, reason);
- Context.getConnectionManager().removeListener(userId, this);
+ connectionManager.removeListener(userId, this);
}
@Override
@@ -92,7 +104,7 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U
private void sendData(Map<String, Collection<?>> data) {
if (isConnected()) {
try {
- getRemote().sendString(Context.getObjectMapper().writeValueAsString(data), null);
+ getRemote().sendString(objectMapper.writeValueAsString(data), null);
} catch (JsonProcessingException e) {
LOGGER.warn("Socket JSON formatting error", e);
}
diff --git a/src/main/java/org/traccar/api/AsyncSocketServlet.java b/src/main/java/org/traccar/api/AsyncSocketServlet.java
index a964ead10..cd2c1639e 100644
--- a/src/main/java/org/traccar/api/AsyncSocketServlet.java
+++ b/src/main/java/org/traccar/api/AsyncSocketServlet.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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,27 +15,48 @@
*/
package org.traccar.api;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.jetty.websocket.server.JettyWebSocketServlet;
import org.eclipse.jetty.websocket.server.JettyWebSocketServletFactory;
-import org.traccar.Context;
import org.traccar.api.resource.SessionResource;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
+import org.traccar.session.ConnectionManager;
+import org.traccar.storage.Storage;
-import javax.servlet.http.HttpSession;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import jakarta.servlet.http.HttpSession;
import java.time.Duration;
+@Singleton
public class AsyncSocketServlet extends JettyWebSocketServlet {
+ private final Config config;
+ private final ObjectMapper objectMapper;
+ private final ConnectionManager connectionManager;
+ private final Storage storage;
+
+ @Inject
+ public AsyncSocketServlet(
+ Config config, ObjectMapper objectMapper, ConnectionManager connectionManager, Storage storage) {
+ this.config = config;
+ this.objectMapper = objectMapper;
+ this.connectionManager = connectionManager;
+ this.storage = storage;
+ }
+
@Override
public void configure(JettyWebSocketServletFactory factory) {
- factory.setIdleTimeout(Duration.ofMillis(Context.getConfig().getLong(Keys.WEB_TIMEOUT)));
+ factory.setIdleTimeout(Duration.ofMillis(config.getLong(Keys.WEB_TIMEOUT)));
factory.setCreator((req, resp) -> {
if (req.getSession() != null) {
- long userId = (Long) ((HttpSession) req.getSession()).getAttribute(SessionResource.USER_ID_KEY);
- return new AsyncSocket(userId);
- } else {
- return null;
+ Long userId = (Long) ((HttpSession) req.getSession()).getAttribute(SessionResource.USER_ID_KEY);
+ if (userId != null) {
+ return new AsyncSocket(objectMapper, connectionManager, storage, userId);
+ }
}
+ return null;
});
}
diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java
index 22756f62a..2aaed2bb5 100644
--- a/src/main/java/org/traccar/api/BaseObjectResource.java
+++ b/src/main/java/org/traccar/api/BaseObjectResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,70 +16,48 @@
*/
package org.traccar.api;
-import java.sql.SQLException;
-import java.util.Set;
-
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.core.Response;
-
-import org.traccar.Context;
-import org.traccar.database.BaseObjectManager;
-import org.traccar.database.ExtendedObjectManager;
-import org.traccar.database.ManagableObjects;
-import org.traccar.database.SimpleObjectManager;
+import org.traccar.api.security.ServiceAccountUser;
import org.traccar.helper.LogAction;
import org.traccar.model.BaseModel;
-import org.traccar.model.Calendar;
-import org.traccar.model.Command;
-import org.traccar.model.Device;
import org.traccar.model.Group;
-import org.traccar.model.GroupedModel;
-import org.traccar.model.ScheduledModel;
+import org.traccar.model.Permission;
import org.traccar.model.User;
+import org.traccar.session.ConnectionManager;
+import org.traccar.session.cache.CacheManager;
import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.core.Response;
public abstract class BaseObjectResource<T extends BaseModel> extends BaseResource {
- private final Class<T> baseClass;
+ @Inject
+ private CacheManager cacheManager;
- public BaseObjectResource(Class<T> baseClass) {
- this.baseClass = baseClass;
- }
+ @Inject
+ private ConnectionManager connectionManager;
- protected final Class<T> getBaseClass() {
- return baseClass;
- }
+ protected final Class<T> baseClass;
- protected final Set<Long> getSimpleManagerItems(BaseObjectManager<T> manager, boolean all, long userId) {
- Set<Long> result;
- if (all) {
- if (Context.getPermissionsManager().getUserAdmin(getUserId())) {
- result = manager.getAllItems();
- } else {
- Context.getPermissionsManager().checkManager(getUserId());
- result = ((ManagableObjects) manager).getManagedItems(getUserId());
- }
- } else {
- if (userId == 0) {
- userId = getUserId();
- }
- Context.getPermissionsManager().checkUser(getUserId(), userId);
- result = ((ManagableObjects) manager).getUserItems(userId);
- }
- return result;
+ public BaseObjectResource(Class<T> baseClass) {
+ this.baseClass = baseClass;
}
@Path("{id}")
@GET
- public Response getSingle(@PathParam("id") long id) throws SQLException {
- Context.getPermissionsManager().checkPermission(baseClass, getUserId(), id);
- BaseObjectManager<T> manager = Context.getManager(baseClass);
- T entity = manager.getById(id);
+ public Response getSingle(@PathParam("id") long id) throws StorageException {
+ permissionsService.checkPermission(baseClass, getUserId(), id);
+ T entity = storage.getObject(baseClass, new Request(
+ new Columns.All(), new Condition.Equals("id", id)));
if (entity != null) {
return Response.ok(entity).build();
} else {
@@ -89,102 +67,66 @@ public abstract class BaseObjectResource<T extends BaseModel> extends BaseResour
@POST
public Response add(T entity) throws StorageException {
- Context.getPermissionsManager().checkReadonly(getUserId());
- if (baseClass.equals(Device.class)) {
- Context.getPermissionsManager().checkDeviceReadonly(getUserId());
- Context.getPermissionsManager().checkDeviceLimit(getUserId());
- } else if (baseClass.equals(Command.class)) {
- Context.getPermissionsManager().checkLimitCommands(getUserId());
- } else if (entity instanceof GroupedModel && ((GroupedModel) entity).getGroupId() != 0) {
- Context.getPermissionsManager().checkPermission(
- Group.class, getUserId(), ((GroupedModel) entity).getGroupId());
- } else if (entity instanceof ScheduledModel && ((ScheduledModel) entity).getCalendarId() != 0) {
- Context.getPermissionsManager().checkPermission(
- Calendar.class, getUserId(), ((ScheduledModel) entity).getCalendarId());
- }
+ permissionsService.checkEdit(getUserId(), entity, true);
- BaseObjectManager<T> manager = Context.getManager(baseClass);
- manager.addItem(entity);
+ entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id"))));
LogAction.create(getUserId(), entity);
- Context.getDataManager().linkObject(User.class, getUserId(), baseClass, entity.getId(), true);
- LogAction.link(getUserId(), User.class, getUserId(), baseClass, entity.getId());
-
- if (manager instanceof SimpleObjectManager) {
- ((SimpleObjectManager<T>) manager).refreshUserItems();
- } else if (baseClass.equals(Group.class) || baseClass.equals(Device.class)) {
- Context.getPermissionsManager().refreshDeviceAndGroupPermissions();
- Context.getPermissionsManager().refreshAllExtendedPermissions();
+ if (getUserId() != ServiceAccountUser.ID) {
+ storage.addPermission(new Permission(User.class, getUserId(), baseClass, entity.getId()));
+ cacheManager.invalidatePermission(true, User.class, getUserId(), baseClass, entity.getId());
+ connectionManager.invalidatePermission(true, User.class, getUserId(), baseClass, entity.getId());
+ LogAction.link(getUserId(), User.class, getUserId(), baseClass, entity.getId());
}
+
return Response.ok(entity).build();
}
@Path("{id}")
@PUT
public Response update(T entity) throws StorageException {
- Context.getPermissionsManager().checkReadonly(getUserId());
- if (baseClass.equals(Device.class)) {
- Context.getPermissionsManager().checkDeviceReadonly(getUserId());
- } else if (baseClass.equals(User.class)) {
- User before = Context.getPermissionsManager().getUser(entity.getId());
- Context.getPermissionsManager().checkUserUpdate(getUserId(), before, (User) entity);
- } else if (baseClass.equals(Command.class)) {
- Context.getPermissionsManager().checkLimitCommands(getUserId());
- } else if (entity instanceof GroupedModel && ((GroupedModel) entity).getGroupId() != 0) {
- Context.getPermissionsManager().checkPermission(
- Group.class, getUserId(), ((GroupedModel) entity).getGroupId());
- } else if (entity instanceof ScheduledModel && ((ScheduledModel) entity).getCalendarId() != 0) {
- Context.getPermissionsManager().checkPermission(
- Calendar.class, getUserId(), ((ScheduledModel) entity).getCalendarId());
+ permissionsService.checkEdit(getUserId(), entity, false);
+ permissionsService.checkPermission(baseClass, getUserId(), entity.getId());
+
+ if (entity instanceof User) {
+ User before = storage.getObject(User.class, new Request(
+ new Columns.All(), new Condition.Equals("id", entity.getId())));
+ permissionsService.checkUserUpdate(getUserId(), before, (User) entity);
+ } else if (entity instanceof Group) {
+ Group group = (Group) entity;
+ if (group.getId() == group.getGroupId()) {
+ throw new IllegalArgumentException("Cycle in group hierarchy");
+ }
}
- Context.getPermissionsManager().checkPermission(baseClass, getUserId(), entity.getId());
- Context.getManager(baseClass).updateItem(entity);
+ storage.updateObject(entity, new Request(
+ new Columns.Exclude("id"),
+ new Condition.Equals("id", entity.getId())));
+ if (entity instanceof User) {
+ User user = (User) entity;
+ if (user.getHashedPassword() != null) {
+ storage.updateObject(entity, new Request(
+ new Columns.Include("hashedPassword", "salt"),
+ new Condition.Equals("id", entity.getId())));
+ }
+ }
+ cacheManager.updateOrInvalidate(true, entity);
LogAction.edit(getUserId(), entity);
- if (baseClass.equals(Group.class) || baseClass.equals(Device.class)) {
- Context.getPermissionsManager().refreshDeviceAndGroupPermissions();
- Context.getPermissionsManager().refreshAllExtendedPermissions();
- }
return Response.ok(entity).build();
}
@Path("{id}")
@DELETE
public Response remove(@PathParam("id") long id) throws StorageException {
- Context.getPermissionsManager().checkReadonly(getUserId());
- if (baseClass.equals(Device.class)) {
- Context.getPermissionsManager().checkDeviceReadonly(getUserId());
- } else if (baseClass.equals(Command.class)) {
- Context.getPermissionsManager().checkLimitCommands(getUserId());
- }
- Context.getPermissionsManager().checkPermission(baseClass, getUserId(), id);
+ permissionsService.checkEdit(getUserId(), baseClass, false);
+ permissionsService.checkPermission(baseClass, getUserId(), id);
+
+ storage.removeObject(baseClass, new Request(new Condition.Equals("id", id)));
+ cacheManager.invalidate(baseClass, id);
- BaseObjectManager<T> manager = Context.getManager(baseClass);
- manager.removeItem(id);
LogAction.remove(getUserId(), baseClass, id);
- if (manager instanceof SimpleObjectManager) {
- ((SimpleObjectManager<T>) manager).refreshUserItems();
- if (manager instanceof ExtendedObjectManager) {
- ((ExtendedObjectManager<T>) manager).refreshExtendedPermissions();
- }
- }
- if (baseClass.equals(Group.class) || baseClass.equals(Device.class) || baseClass.equals(User.class)) {
- if (baseClass.equals(Group.class)) {
- Context.getGroupsManager().refreshItems();
- Context.getDeviceManager().updateDeviceCache(true);
- }
- Context.getPermissionsManager().refreshDeviceAndGroupPermissions();
- if (baseClass.equals(User.class)) {
- Context.getPermissionsManager().refreshAllUsersPermissions();
- } else {
- Context.getPermissionsManager().refreshAllExtendedPermissions();
- }
- } else if (baseClass.equals(Calendar.class)) {
- Context.getGeofenceManager().refreshItems();
- Context.getNotificationManager().refreshItems();
- }
return Response.noContent().build();
}
diff --git a/src/main/java/org/traccar/api/BaseResource.java b/src/main/java/org/traccar/api/BaseResource.java
index 6dff8c8c3..f20b8c4c2 100644
--- a/src/main/java/org/traccar/api/BaseResource.java
+++ b/src/main/java/org/traccar/api/BaseResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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,16 +15,25 @@
*/
package org.traccar.api;
+import org.traccar.api.security.PermissionsService;
import org.traccar.api.security.UserPrincipal;
+import org.traccar.storage.Storage;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.SecurityContext;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.SecurityContext;
public class BaseResource {
@Context
private SecurityContext securityContext;
+ @Inject
+ protected Storage storage;
+
+ @Inject
+ protected PermissionsService permissionsService;
+
protected long getUserId() {
UserPrincipal principal = (UserPrincipal) securityContext.getUserPrincipal();
if (principal != null) {
@@ -32,4 +41,5 @@ public class BaseResource {
}
return 0;
}
+
}
diff --git a/src/main/java/org/traccar/api/CorsResponseFilter.java b/src/main/java/org/traccar/api/CorsResponseFilter.java
index 91aea5718..a380eb41d 100644
--- a/src/main/java/org/traccar/api/CorsResponseFilter.java
+++ b/src/main/java/org/traccar/api/CorsResponseFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -16,16 +16,26 @@
package org.traccar.api;
import io.netty.handler.codec.http.HttpHeaderNames;
-import org.traccar.Context;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
-import javax.ws.rs.container.ContainerRequestContext;
-import javax.ws.rs.container.ContainerResponseContext;
-import javax.ws.rs.container.ContainerResponseFilter;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerResponseContext;
+import jakarta.ws.rs.container.ContainerResponseFilter;
import java.io.IOException;
+@Singleton
public class CorsResponseFilter implements ContainerResponseFilter {
+ private final String allowed;
+
+ @Inject
+ public CorsResponseFilter(Config config) {
+ allowed = config.getString(Keys.WEB_ORIGIN);
+ }
+
private static final String ORIGIN_ALL = "*";
private static final String HEADERS_ALL = "origin, content-type, accept, authorization";
private static final String METHODS_ALL = "GET, POST, PUT, DELETE, OPTIONS";
@@ -46,8 +56,6 @@ public class CorsResponseFilter implements ContainerResponseFilter {
if (!response.getHeaders().containsKey(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.toString())) {
String origin = request.getHeaderString(HttpHeaderNames.ORIGIN.toString());
- String allowed = Context.getConfig().getString(Keys.WEB_ORIGIN);
-
if (origin == null) {
response.getHeaders().add(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.toString(), ORIGIN_ALL);
} else if (allowed == null || allowed.equals(ORIGIN_ALL) || allowed.contains(origin)) {
diff --git a/src/main/java/org/traccar/api/DateParameterConverterProvider.java b/src/main/java/org/traccar/api/DateParameterConverterProvider.java
index f07ece984..4858fcbfd 100644
--- a/src/main/java/org/traccar/api/DateParameterConverterProvider.java
+++ b/src/main/java/org/traccar/api/DateParameterConverterProvider.java
@@ -17,8 +17,8 @@ package org.traccar.api;
import org.traccar.helper.DateUtil;
-import javax.ws.rs.ext.ParamConverter;
-import javax.ws.rs.ext.ParamConverterProvider;
+import jakarta.ws.rs.ext.ParamConverter;
+import jakarta.ws.rs.ext.ParamConverterProvider;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Date;
diff --git a/src/main/java/org/traccar/api/ExtendedObjectResource.java b/src/main/java/org/traccar/api/ExtendedObjectResource.java
index 9e554217e..348ebe38a 100644
--- a/src/main/java/org/traccar/api/ExtendedObjectResource.java
+++ b/src/main/java/org/traccar/api/ExtendedObjectResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,19 @@
*/
package org.traccar.api;
-import java.sql.SQLException;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.QueryParam;
-
-import org.traccar.Context;
-import org.traccar.database.ExtendedObjectManager;
import org.traccar.model.BaseModel;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.model.User;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.QueryParam;
+import java.util.Collection;
+import java.util.LinkedList;
public class ExtendedObjectResource<T extends BaseModel> extends BaseObjectResource<T> {
@@ -36,27 +38,34 @@ public class ExtendedObjectResource<T extends BaseModel> extends BaseObjectResou
@GET
public Collection<T> get(
- @QueryParam("all") boolean all, @QueryParam("userId") long userId, @QueryParam("groupId") long groupId,
- @QueryParam("deviceId") long deviceId, @QueryParam("refresh") boolean refresh) throws SQLException {
-
- ExtendedObjectManager<T> manager = (ExtendedObjectManager<T>) Context.getManager(getBaseClass());
- if (refresh) {
- manager.refreshItems();
- }
+ @QueryParam("all") boolean all, @QueryParam("userId") long userId,
+ @QueryParam("groupId") long groupId, @QueryParam("deviceId") long deviceId) throws StorageException {
- Set<Long> result = new HashSet<>(getSimpleManagerItems(manager, all, userId));
+ var conditions = new LinkedList<Condition>();
- if (groupId != 0) {
- Context.getPermissionsManager().checkGroup(getUserId(), groupId);
- result.retainAll(manager.getGroupItems(groupId));
+ if (all) {
+ if (permissionsService.notAdmin(getUserId())) {
+ conditions.add(new Condition.Permission(User.class, getUserId(), baseClass));
+ }
+ } else {
+ if (userId == 0) {
+ conditions.add(new Condition.Permission(User.class, getUserId(), baseClass));
+ } else {
+ permissionsService.checkUser(getUserId(), userId);
+ conditions.add(new Condition.Permission(User.class, userId, baseClass).excludeGroups());
+ }
}
- if (deviceId != 0) {
- Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
- result.retainAll(manager.getDeviceItems(deviceId));
+ if (groupId > 0) {
+ permissionsService.checkPermission(Group.class, getUserId(), groupId);
+ conditions.add(new Condition.Permission(Group.class, groupId, baseClass).excludeGroups());
+ }
+ if (deviceId > 0) {
+ permissionsService.checkPermission(Device.class, getUserId(), deviceId);
+ conditions.add(new Condition.Permission(Device.class, deviceId, baseClass).excludeGroups());
}
- return manager.getItems(result);
+ return storage.getObjects(baseClass, new Request(new Columns.All(), Condition.merge(conditions)));
}
}
diff --git a/src/main/java/org/traccar/api/MediaFilter.java b/src/main/java/org/traccar/api/MediaFilter.java
index 77731a810..38d13078d 100644
--- a/src/main/java/org/traccar/api/MediaFilter.java
+++ b/src/main/java/org/traccar/api/MediaFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,35 +16,50 @@
*/
package org.traccar.api;
-import java.io.IOException;
-import java.sql.SQLException;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import org.traccar.Context;
-import org.traccar.Main;
+import com.google.inject.Provider;
import org.traccar.api.resource.SessionResource;
+import org.traccar.api.security.PermissionsService;
import org.traccar.database.StatisticsManager;
import org.traccar.helper.Log;
import org.traccar.model.Device;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
+import java.io.IOException;
+
+@Singleton
public class MediaFilter implements Filter {
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
+ private final Storage storage;
+ private final StatisticsManager statisticsManager;
+ private final Provider<PermissionsService> permissionsServiceProvider;
+
+ @Inject
+ public MediaFilter(
+ Storage storage, StatisticsManager statisticsManager,
+ Provider<PermissionsService> permissionsServiceProvider) {
+ this.storage = storage;
+ this.statisticsManager = statisticsManager;
+ this.permissionsServiceProvider = permissionsServiceProvider;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
+
HttpServletResponse httpResponse = (HttpServletResponse) response;
try {
HttpSession session = ((HttpServletRequest) request).getSession(false);
@@ -52,8 +67,7 @@ public class MediaFilter implements Filter {
if (session != null) {
userId = (Long) session.getAttribute(SessionResource.USER_ID_KEY);
if (userId != null) {
- Context.getPermissionsManager().checkUserEnabled(userId);
- Main.getInjector().getInstance(StatisticsManager.class).registerRequest(userId);
+ statisticsManager.registerRequest(userId);
}
}
if (userId == null) {
@@ -64,26 +78,20 @@ public class MediaFilter implements Filter {
String path = ((HttpServletRequest) request).getPathInfo();
String[] parts = path != null ? path.split("/") : null;
if (parts != null && parts.length >= 2) {
- Device device = Context.getDeviceManager().getByUniqueId(parts[1]);
+ Device device = storage.getObject(Device.class, new Request(
+ new Columns.All(), new Condition.Equals("uniqueId", parts[1])));
if (device != null) {
- Context.getPermissionsManager().checkDevice(userId, device.getId());
+ permissionsServiceProvider.get().checkPermission(Device.class, userId, device.getId());
chain.doFilter(request, response);
return;
}
}
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
- } catch (SecurityException e) {
+ } catch (SecurityException | StorageException e) {
httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
httpResponse.getWriter().println(Log.exceptionStack(e));
- } catch (SQLException e) {
- httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
- httpResponse.getWriter().println(Log.exceptionStack(e));
}
}
- @Override
- public void destroy() {
- }
-
}
diff --git a/src/main/java/org/traccar/api/ResourceErrorHandler.java b/src/main/java/org/traccar/api/ResourceErrorHandler.java
index 108a8e8cc..387f3db6a 100644
--- a/src/main/java/org/traccar/api/ResourceErrorHandler.java
+++ b/src/main/java/org/traccar/api/ResourceErrorHandler.java
@@ -17,9 +17,9 @@ package org.traccar.api;
import org.traccar.helper.Log;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.ext.ExceptionMapper;
public class ResourceErrorHandler implements ExceptionMapper<Exception> {
diff --git a/src/main/java/org/traccar/api/SimpleObjectResource.java b/src/main/java/org/traccar/api/SimpleObjectResource.java
index a7fcae0e7..c9d41b063 100644
--- a/src/main/java/org/traccar/api/SimpleObjectResource.java
+++ b/src/main/java/org/traccar/api/SimpleObjectResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,17 @@
*/
package org.traccar.api;
-import java.sql.SQLException;
-import java.util.Collection;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.QueryParam;
-
-import org.traccar.Context;
-import org.traccar.database.BaseObjectManager;
import org.traccar.model.BaseModel;
+import org.traccar.model.User;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.QueryParam;
+import java.util.Collection;
+import java.util.LinkedList;
public class SimpleObjectResource<T extends BaseModel> extends BaseObjectResource<T> {
@@ -34,10 +36,24 @@ public class SimpleObjectResource<T extends BaseModel> extends BaseObjectResourc
@GET
public Collection<T> get(
- @QueryParam("all") boolean all, @QueryParam("userId") long userId) throws SQLException {
-
- BaseObjectManager<T> manager = Context.getManager(getBaseClass());
- return manager.getItems(getSimpleManagerItems(manager, all, userId));
+ @QueryParam("all") boolean all, @QueryParam("userId") long userId) throws StorageException {
+
+ var conditions = new LinkedList<Condition>();
+
+ if (all) {
+ if (permissionsService.notAdmin(getUserId())) {
+ conditions.add(new Condition.Permission(User.class, getUserId(), baseClass));
+ }
+ } else {
+ if (userId == 0) {
+ userId = getUserId();
+ } else {
+ permissionsService.checkUser(getUserId(), userId);
+ }
+ conditions.add(new Condition.Permission(User.class, userId, baseClass));
+ }
+
+ return storage.getObjects(baseClass, new Request(new Columns.All(), Condition.merge(conditions)));
}
}
diff --git a/src/main/java/org/traccar/api/resource/AttributeResource.java b/src/main/java/org/traccar/api/resource/AttributeResource.java
index d2dc28903..44f0ef452 100644
--- a/src/main/java/org/traccar/api/resource/AttributeResource.java
+++ b/src/main/java/org/traccar/api/resource/AttributeResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,80 +16,84 @@
*/
package org.traccar.api.resource;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
-import org.traccar.Context;
import org.traccar.api.ExtendedObjectResource;
import org.traccar.model.Attribute;
+import org.traccar.model.Device;
import org.traccar.model.Position;
import org.traccar.handler.ComputedAttributesHandler;
import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
@Path("attributes/computed")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class AttributeResource extends ExtendedObjectResource<Attribute> {
+ @Inject
+ private ComputedAttributesHandler computedAttributesHandler;
+
public AttributeResource() {
super(Attribute.class);
}
@POST
@Path("test")
- public Response test(@QueryParam("deviceId") long deviceId, Attribute entity) {
- Context.getPermissionsManager().checkAdmin(getUserId());
- Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
- Position last = Context.getIdentityManager().getLastPosition(deviceId);
- if (last != null) {
- Object result = new ComputedAttributesHandler(
- Context.getConfig(),
- Context.getIdentityManager(),
- Context.getAttributesManager()).computeAttribute(entity, last);
- if (result != null) {
- switch (entity.getType()) {
- case "number":
- Number numberValue = (Number) result;
- return Response.ok(numberValue).build();
- case "boolean":
- Boolean booleanValue = (Boolean) result;
- return Response.ok(booleanValue).build();
- default:
- return Response.ok(result.toString()).build();
- }
- } else {
- return Response.noContent().build();
+ public Response test(@QueryParam("deviceId") long deviceId, Attribute entity) throws StorageException {
+ permissionsService.checkAdmin(getUserId());
+ permissionsService.checkPermission(Device.class, getUserId(), deviceId);
+
+ Position position = storage.getObject(Position.class, new Request(
+ new Columns.All(),
+ new Condition.LatestPositions(deviceId)));
+
+ Object result = computedAttributesHandler.computeAttribute(entity, position);
+ if (result != null) {
+ switch (entity.getType()) {
+ case "number":
+ Number numberValue = (Number) result;
+ return Response.ok(numberValue).build();
+ case "boolean":
+ Boolean booleanValue = (Boolean) result;
+ return Response.ok(booleanValue).build();
+ default:
+ return Response.ok(result.toString()).build();
}
} else {
- throw new IllegalArgumentException("Device has no last position");
+ return Response.noContent().build();
}
}
@POST
public Response add(Attribute entity) throws StorageException {
- Context.getPermissionsManager().checkAdmin(getUserId());
+ permissionsService.checkAdmin(getUserId());
return super.add(entity);
}
@Path("{id}")
@PUT
public Response update(Attribute entity) throws StorageException {
- Context.getPermissionsManager().checkAdmin(getUserId());
+ permissionsService.checkAdmin(getUserId());
return super.update(entity);
}
@Path("{id}")
@DELETE
public Response remove(@PathParam("id") long id) throws StorageException {
- Context.getPermissionsManager().checkAdmin(getUserId());
+ permissionsService.checkAdmin(getUserId());
return super.remove(id);
}
diff --git a/src/main/java/org/traccar/api/resource/CalendarResource.java b/src/main/java/org/traccar/api/resource/CalendarResource.java
index 9399c34a5..f6c1f3c59 100644
--- a/src/main/java/org/traccar/api/resource/CalendarResource.java
+++ b/src/main/java/org/traccar/api/resource/CalendarResource.java
@@ -16,10 +16,10 @@
*/
package org.traccar.api.resource;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
import org.traccar.api.SimpleObjectResource;
import org.traccar.model.Calendar;
diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java
index a31345246..d50c7ee0c 100644
--- a/src/main/java/org/traccar/api/resource/CommandResource.java
+++ b/src/main/java/org/traccar/api/resource/CommandResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2016 Gabor Somogyi (gabor.g.somogyi@gmail.com)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
@@ -17,76 +17,153 @@
*/
package org.traccar.api.resource;
-import org.traccar.Context;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.BaseProtocol;
+import org.traccar.ServerManager;
import org.traccar.api.ExtendedObjectResource;
import org.traccar.database.CommandsManager;
+import org.traccar.helper.model.DeviceUtil;
import org.traccar.model.Command;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.model.Position;
+import org.traccar.model.QueuedCommand;
import org.traccar.model.Typed;
+import org.traccar.model.User;
+import org.traccar.model.UserRestrictions;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
@Path("commands")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class CommandResource extends ExtendedObjectResource<Command> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(CommandResource.class);
+
+ @Inject
+ private CommandsManager commandsManager;
+
+ @Inject
+ private ServerManager serverManager;
+
public CommandResource() {
super(Command.class);
}
+ private BaseProtocol getDeviceProtocol(long deviceId) throws StorageException {
+ Position position = storage.getObject(Position.class, new Request(
+ new Columns.All(), new Condition.LatestPositions(deviceId)));
+ if (position != null) {
+ return serverManager.getProtocol(position.getProtocol());
+ } else {
+ return null;
+ }
+ }
+
@GET
@Path("send")
- public Collection<Command> get(@QueryParam("deviceId") long deviceId) {
- Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
- CommandsManager commandsManager = Context.getCommandsManager();
- Set<Long> result = new HashSet<>(commandsManager.getUserItems(getUserId()));
- result.retainAll(commandsManager.getSupportedCommands(deviceId));
- return commandsManager.getItems(result);
+ public Collection<Command> get(@QueryParam("deviceId") long deviceId) throws StorageException {
+ permissionsService.checkPermission(Device.class, getUserId(), deviceId);
+ BaseProtocol protocol = getDeviceProtocol(deviceId);
+
+ var commands = storage.getObjects(baseClass, new Request(
+ new Columns.All(),
+ Condition.merge(List.of(
+ new Condition.Permission(User.class, getUserId(), baseClass),
+ new Condition.Permission(Device.class, deviceId, baseClass)
+ ))));
+
+ return commands.stream().filter(command -> {
+ String type = command.getType();
+ if (protocol != null) {
+ return command.getTextChannel() && protocol.getSupportedTextCommands().contains(type)
+ || !command.getTextChannel() && protocol.getSupportedDataCommands().contains(type);
+ } else {
+ return type.equals(Command.TYPE_CUSTOM);
+ }
+ }).collect(Collectors.toList());
}
@POST
@Path("send")
- public Response send(Command entity) throws Exception {
- Context.getPermissionsManager().checkReadonly(getUserId());
- long deviceId = entity.getDeviceId();
- long id = entity.getId();
- Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
- if (id != 0) {
- Context.getPermissionsManager().checkPermission(Command.class, getUserId(), id);
- Context.getPermissionsManager().checkUserDeviceCommand(getUserId(), deviceId, id);
+ public Response send(Command entity, @QueryParam("groupId") long groupId) throws Exception {
+ if (entity.getId() > 0) {
+ permissionsService.checkPermission(baseClass, getUserId(), entity.getId());
+ long deviceId = entity.getDeviceId();
+ entity = storage.getObject(baseClass, new Request(
+ new Columns.All(), new Condition.Equals("id", entity.getId())));
+ entity.setDeviceId(deviceId);
} else {
- Context.getPermissionsManager().checkLimitCommands(getUserId());
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getLimitCommands);
}
- if (!Context.getCommandsManager().sendCommand(entity)) {
- return Response.accepted(entity).build();
+ boolean result = true;
+ if (groupId > 0) {
+ permissionsService.checkPermission(Group.class, getUserId(), groupId);
+ var devices = DeviceUtil.getAccessibleDevices(storage, getUserId(), List.of(), List.of(groupId));
+ for (Device device : devices) {
+ Command command = QueuedCommand.fromCommand(entity).toCommand();
+ command.setDeviceId(device.getId());
+ result = commandsManager.sendCommand(command) && result;
+ }
+ } else {
+ permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId());
+ result = commandsManager.sendCommand(entity);
}
- return Response.ok(entity).build();
+ return result ? Response.ok(entity).build() : Response.accepted(entity).build();
}
@GET
@Path("types")
public Collection<Typed> get(
@QueryParam("deviceId") long deviceId,
- @QueryParam("protocol") String protocol,
- @QueryParam("textChannel") boolean textChannel) {
+ @QueryParam("textChannel") boolean textChannel) throws StorageException {
if (deviceId != 0) {
- Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
- return Context.getCommandsManager().getCommandTypes(deviceId, textChannel);
- } else if (protocol != null) {
- return Context.getCommandsManager().getCommandTypes(protocol, textChannel);
+ permissionsService.checkPermission(Device.class, getUserId(), deviceId);
+ BaseProtocol protocol = getDeviceProtocol(deviceId);
+ if (protocol != null) {
+ if (textChannel) {
+ return protocol.getSupportedTextCommands().stream().map(Typed::new).collect(Collectors.toList());
+ } else {
+ return protocol.getSupportedDataCommands().stream().map(Typed::new).collect(Collectors.toList());
+ }
+ } else {
+ return Collections.singletonList(new Typed(Command.TYPE_CUSTOM));
+ }
} else {
- return Context.getCommandsManager().getAllCommandTypes();
+ List<Typed> result = new ArrayList<>();
+ Field[] fields = Command.class.getDeclaredFields();
+ for (Field field : fields) {
+ if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("TYPE_")) {
+ try {
+ result.add(new Typed(field.get(null).toString()));
+ } catch (IllegalArgumentException | IllegalAccessException error) {
+ LOGGER.warn("Get command types error", error);
+ }
+ }
+ }
+ return result;
}
}
+
}
diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java
index 9436b59f6..61a70bac0 100644
--- a/src/main/java/org/traccar/api/resource/DeviceResource.java
+++ b/src/main/java/org/traccar/api/resource/DeviceResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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,34 +15,58 @@
*/
package org.traccar.api.resource;
-import org.traccar.Context;
import org.traccar.api.BaseObjectResource;
-import org.traccar.database.DeviceManager;
+import org.traccar.broadcast.BroadcastService;
+import org.traccar.database.MediaManager;
import org.traccar.helper.LogAction;
import org.traccar.model.Device;
import org.traccar.model.DeviceAccumulators;
+import org.traccar.model.Position;
+import org.traccar.model.User;
+import org.traccar.session.ConnectionManager;
+import org.traccar.session.cache.CacheManager;
import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import java.sql.SQLException;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.HeaderParam;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.util.Collection;
-import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
-import java.util.Set;
@Path("devices")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class DeviceResource extends BaseObjectResource<Device> {
+ @Inject
+ private CacheManager cacheManager;
+
+ @Inject
+ private ConnectionManager connectionManager;
+
+ @Inject
+ private BroadcastService broadcastService;
+
+ @Inject
+ private MediaManager mediaManager;
+
public DeviceResource() {
super(Device.class);
}
@@ -51,51 +75,112 @@ public class DeviceResource extends BaseObjectResource<Device> {
public Collection<Device> get(
@QueryParam("all") boolean all, @QueryParam("userId") long userId,
@QueryParam("uniqueId") List<String> uniqueIds,
- @QueryParam("id") List<Long> deviceIds) throws SQLException {
- DeviceManager deviceManager = Context.getDeviceManager();
- Set<Long> result;
- if (all) {
- if (Context.getPermissionsManager().getUserAdmin(getUserId())) {
- result = deviceManager.getAllItems();
- } else {
- Context.getPermissionsManager().checkManager(getUserId());
- result = deviceManager.getManagedItems(getUserId());
- }
- } else if (uniqueIds.isEmpty() && deviceIds.isEmpty()) {
- if (userId == 0) {
- userId = getUserId();
- }
- Context.getPermissionsManager().checkUser(getUserId(), userId);
- if (Context.getPermissionsManager().getUserAdmin(getUserId())) {
- result = deviceManager.getAllUserItems(userId);
- } else {
- result = deviceManager.getUserItems(userId);
- }
- } else {
- result = new HashSet<>();
+ @QueryParam("id") List<Long> deviceIds) throws StorageException {
+
+ if (!uniqueIds.isEmpty() || !deviceIds.isEmpty()) {
+
+ List<Device> result = new LinkedList<>();
for (String uniqueId : uniqueIds) {
- Device device = deviceManager.getByUniqueId(uniqueId);
- Context.getPermissionsManager().checkDevice(getUserId(), device.getId());
- result.add(device.getId());
+ result.addAll(storage.getObjects(Device.class, new Request(
+ new Columns.All(),
+ new Condition.And(
+ new Condition.Equals("uniqueId", uniqueId),
+ new Condition.Permission(User.class, getUserId(), Device.class)))));
}
for (Long deviceId : deviceIds) {
- Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
- result.add(deviceId);
+ result.addAll(storage.getObjects(Device.class, new Request(
+ new Columns.All(),
+ new Condition.And(
+ new Condition.Equals("id", deviceId),
+ new Condition.Permission(User.class, getUserId(), Device.class)))));
}
+ return result;
+
+ } else {
+
+ var conditions = new LinkedList<Condition>();
+
+ if (all) {
+ if (permissionsService.notAdmin(getUserId())) {
+ conditions.add(new Condition.Permission(User.class, getUserId(), baseClass));
+ }
+ } else {
+ if (userId == 0) {
+ conditions.add(new Condition.Permission(User.class, getUserId(), baseClass));
+ } else {
+ permissionsService.checkUser(getUserId(), userId);
+ conditions.add(new Condition.Permission(User.class, userId, baseClass).excludeGroups());
+ }
+ }
+
+ return storage.getObjects(baseClass, new Request(new Columns.All(), Condition.merge(conditions)));
+
}
- return deviceManager.getItems(result);
}
@Path("{id}/accumulators")
@PUT
public Response updateAccumulators(DeviceAccumulators entity) throws StorageException {
- if (!Context.getPermissionsManager().getUserAdmin(getUserId())) {
- Context.getPermissionsManager().checkManager(getUserId());
- Context.getPermissionsManager().checkPermission(Device.class, getUserId(), entity.getDeviceId());
+ if (permissionsService.notAdmin(getUserId())) {
+ permissionsService.checkManager(getUserId());
+ permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId());
}
- Context.getDeviceManager().resetDeviceAccumulators(entity);
+
+ Position position = storage.getObject(Position.class, new Request(
+ new Columns.All(), new Condition.LatestPositions(entity.getDeviceId())));
+ if (position != null) {
+ if (entity.getTotalDistance() != null) {
+ position.getAttributes().put(Position.KEY_TOTAL_DISTANCE, entity.getTotalDistance());
+ }
+ if (entity.getHours() != null) {
+ position.getAttributes().put(Position.KEY_HOURS, entity.getHours());
+ }
+ position.setId(storage.addObject(position, new Request(new Columns.Exclude("id"))));
+
+ Device device = new Device();
+ device.setId(position.getDeviceId());
+ device.setPositionId(position.getId());
+ storage.updateObject(device, new Request(
+ new Columns.Include("positionId"),
+ new Condition.Equals("id", device.getId())));
+
+ try {
+ cacheManager.addDevice(position.getDeviceId());
+ cacheManager.updatePosition(position);
+ connectionManager.updatePosition(true, position);
+ } finally {
+ cacheManager.removeDevice(position.getDeviceId());
+ }
+ } else {
+ throw new IllegalArgumentException();
+ }
+
LogAction.resetDeviceAccumulators(getUserId(), entity.getDeviceId());
return Response.noContent().build();
}
+ @Path("{id}/image")
+ @POST
+ @Consumes("image/*")
+ public Response uploadImage(
+ @PathParam("id") long deviceId, File file,
+ @HeaderParam(HttpHeaders.CONTENT_TYPE) String type) throws StorageException, IOException {
+
+ Device device = storage.getObject(Device.class, new Request(
+ new Columns.All(),
+ new Condition.And(
+ new Condition.Equals("id", deviceId),
+ new Condition.Permission(User.class, getUserId(), Device.class))));
+ if (device != null) {
+ String name = "device";
+ String extension = type.substring("image/".length());
+ try (var input = new FileInputStream(file);
+ var output = mediaManager.createFileStream(device.getUniqueId(), name, extension)) {
+ input.transferTo(output);
+ }
+ return Response.ok(name + "." + extension).build();
+ }
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+
}
diff --git a/src/main/java/org/traccar/api/resource/DriverResource.java b/src/main/java/org/traccar/api/resource/DriverResource.java
index 91aa54c5e..19cf74f39 100644
--- a/src/main/java/org/traccar/api/resource/DriverResource.java
+++ b/src/main/java/org/traccar/api/resource/DriverResource.java
@@ -16,10 +16,10 @@
*/
package org.traccar.api.resource;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
import org.traccar.api.ExtendedObjectResource;
import org.traccar.model.Driver;
diff --git a/src/main/java/org/traccar/api/resource/EventResource.java b/src/main/java/org/traccar/api/resource/EventResource.java
index 354d96e4f..1f20b880d 100644
--- a/src/main/java/org/traccar/api/resource/EventResource.java
+++ b/src/main/java/org/traccar/api/resource/EventResource.java
@@ -15,21 +15,22 @@
*/
package org.traccar.api.resource;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import org.traccar.Context;
import org.traccar.api.BaseResource;
+import org.traccar.model.Device;
import org.traccar.model.Event;
-import org.traccar.model.Geofence;
-import org.traccar.model.Maintenance;
import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
@Path("events")
@Produces(MediaType.APPLICATION_JSON)
@@ -39,17 +40,12 @@ public class EventResource extends BaseResource {
@Path("{id}")
@GET
public Event get(@PathParam("id") long id) throws StorageException {
- Event event = Context.getDataManager().getObject(Event.class, id);
+ Event event = storage.getObject(Event.class, new Request(
+ new Columns.All(), new Condition.Equals("id", id)));
if (event == null) {
throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
}
- Context.getPermissionsManager().checkDevice(getUserId(), event.getDeviceId());
- if (event.getGeofenceId() != 0) {
- Context.getPermissionsManager().checkPermission(Geofence.class, getUserId(), event.getGeofenceId());
- }
- if (event.getMaintenanceId() != 0) {
- Context.getPermissionsManager().checkPermission(Maintenance.class, getUserId(), event.getMaintenanceId());
- }
+ permissionsService.checkPermission(Device.class, getUserId(), event.getDeviceId());
return event;
}
diff --git a/src/main/java/org/traccar/api/resource/GeofenceResource.java b/src/main/java/org/traccar/api/resource/GeofenceResource.java
index 58f2c188c..030690889 100644
--- a/src/main/java/org/traccar/api/resource/GeofenceResource.java
+++ b/src/main/java/org/traccar/api/resource/GeofenceResource.java
@@ -18,10 +18,10 @@ package org.traccar.api.resource;
import org.traccar.api.ExtendedObjectResource;
import org.traccar.model.Geofence;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
@Path("geofences")
@Produces(MediaType.APPLICATION_JSON)
diff --git a/src/main/java/org/traccar/api/resource/GroupResource.java b/src/main/java/org/traccar/api/resource/GroupResource.java
index fcea15d0a..628f8f655 100644
--- a/src/main/java/org/traccar/api/resource/GroupResource.java
+++ b/src/main/java/org/traccar/api/resource/GroupResource.java
@@ -18,10 +18,10 @@ package org.traccar.api.resource;
import org.traccar.api.SimpleObjectResource;
import org.traccar.model.Group;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
@Path("groups")
@Produces(MediaType.APPLICATION_JSON)
diff --git a/src/main/java/org/traccar/api/resource/MaintenanceResource.java b/src/main/java/org/traccar/api/resource/MaintenanceResource.java
index fa1b359ce..12841e497 100644
--- a/src/main/java/org/traccar/api/resource/MaintenanceResource.java
+++ b/src/main/java/org/traccar/api/resource/MaintenanceResource.java
@@ -16,10 +16,10 @@
*/
package org.traccar.api.resource;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
import org.traccar.api.ExtendedObjectResource;
import org.traccar.model.Maintenance;
diff --git a/src/main/java/org/traccar/api/resource/NotificationResource.java b/src/main/java/org/traccar/api/resource/NotificationResource.java
index 9631a52b7..2a209efb6 100644
--- a/src/main/java/org/traccar/api/resource/NotificationResource.java
+++ b/src/main/java/org/traccar/api/resource/NotificationResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,30 +15,42 @@
*/
package org.traccar.api.resource;
-import java.util.Collection;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import org.traccar.Context;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.traccar.api.ExtendedObjectResource;
import org.traccar.model.Event;
import org.traccar.model.Notification;
import org.traccar.model.Typed;
+import org.traccar.model.User;
import org.traccar.notification.MessageException;
+import org.traccar.notification.NotificatorManager;
+import org.traccar.storage.StorageException;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
@Path("notifications")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class NotificationResource extends ExtendedObjectResource<Notification> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(NotificationResource.class);
+
+ @Inject
+ private NotificatorManager notificatorManager;
+
public NotificationResource() {
super(Notification.class);
}
@@ -46,21 +58,32 @@ public class NotificationResource extends ExtendedObjectResource<Notification> {
@GET
@Path("types")
public Collection<Typed> get() {
- return Context.getNotificationManager().getAllNotificationTypes();
+ List<Typed> types = new LinkedList<>();
+ Field[] fields = Event.class.getDeclaredFields();
+ for (Field field : fields) {
+ if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("TYPE_")) {
+ try {
+ types.add(new Typed(field.get(null).toString()));
+ } catch (IllegalArgumentException | IllegalAccessException error) {
+ LOGGER.warn("Get event types error", error);
+ }
+ }
+ }
+ return types;
}
@GET
@Path("notificators")
public Collection<Typed> getNotificators() {
- return Context.getNotificatorManager().getAllNotificatorTypes();
+ return notificatorManager.getAllNotificatorTypes();
}
@POST
@Path("test")
- public Response testMessage() throws MessageException, InterruptedException {
- for (Typed method : Context.getNotificatorManager().getAllNotificatorTypes()) {
- Context.getNotificatorManager()
- .getNotificator(method.getType()).sendSync(getUserId(), new Event("test", 0), null);
+ public Response testMessage() throws MessageException, StorageException {
+ User user = permissionsService.getUser(getUserId());
+ for (Typed method : notificatorManager.getAllNotificatorTypes()) {
+ notificatorManager.getNotificator(method.getType()).send(null, user, new Event("test", 0), null);
}
return Response.noContent().build();
}
@@ -68,8 +91,9 @@ public class NotificationResource extends ExtendedObjectResource<Notification> {
@POST
@Path("test/{notificator}")
public Response testMessage(@PathParam("notificator") String notificator)
- throws MessageException, InterruptedException {
- Context.getNotificatorManager().getNotificator(notificator).sendSync(getUserId(), new Event("test", 0), null);
+ throws MessageException, StorageException {
+ User user = permissionsService.getUser(getUserId());
+ notificatorManager.getNotificator(notificator).send(null, user, new Event("test", 0), null);
return Response.noContent().build();
}
diff --git a/src/main/java/org/traccar/api/resource/OrderResource.java b/src/main/java/org/traccar/api/resource/OrderResource.java
index 77608a508..3852b975f 100644
--- a/src/main/java/org/traccar/api/resource/OrderResource.java
+++ b/src/main/java/org/traccar/api/resource/OrderResource.java
@@ -18,10 +18,10 @@ package org.traccar.api.resource;
import org.traccar.api.SimpleObjectResource;
import org.traccar.model.Order;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
@Path("orders")
@Produces(MediaType.APPLICATION_JSON)
diff --git a/src/main/java/org/traccar/api/resource/PasswordResource.java b/src/main/java/org/traccar/api/resource/PasswordResource.java
index 0642ff3cc..029e63a0c 100644
--- a/src/main/java/org/traccar/api/resource/PasswordResource.java
+++ b/src/main/java/org/traccar/api/resource/PasswordResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2021 - 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,49 +15,55 @@
*/
package org.traccar.api.resource;
-import org.apache.velocity.VelocityContext;
-import org.traccar.Context;
import org.traccar.api.BaseResource;
+import org.traccar.api.signature.TokenManager;
+import org.traccar.mail.MailManager;
import org.traccar.model.User;
-import org.traccar.notification.NotificationMessage;
import org.traccar.notification.TextTemplateFormatter;
import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
-import javax.annotation.security.PermitAll;
-import javax.mail.MessagingException;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.FormParam;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.util.UUID;
+import jakarta.annotation.security.PermitAll;
+import jakarta.inject.Inject;
+import jakarta.mail.MessagingException;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.FormParam;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
@Path("password")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public class PasswordResource extends BaseResource {
- private static final String PASSWORD_RESET_TOKEN = "passwordToken";
+ @Inject
+ private MailManager mailManager;
+
+ @Inject
+ private TokenManager tokenManager;
+
+ @Inject
+ private TextTemplateFormatter textTemplateFormatter;
@Path("reset")
@PermitAll
@POST
- public Response reset(@FormParam("email") String email) throws StorageException, MessagingException {
- for (long userId : Context.getUsersManager().getAllItems()) {
- User user = Context.getUsersManager().getById(userId);
- if (email.equals(user.getEmail())) {
- String token = UUID.randomUUID().toString().replaceAll("-", "");
- user.set(PASSWORD_RESET_TOKEN, token);
- Context.getUsersManager().updateItem(user);
- VelocityContext velocityContext = TextTemplateFormatter.prepareContext(null);
- velocityContext.put("token", token);
- NotificationMessage fullMessage =
- TextTemplateFormatter.formatMessage(velocityContext, "passwordReset", "full");
- Context.getMailManager().sendMessage(userId, fullMessage.getSubject(), fullMessage.getBody());
- break;
- }
+ public Response reset(@FormParam("email") String email)
+ throws StorageException, MessagingException, GeneralSecurityException, IOException {
+
+ User user = storage.getObject(User.class, new Request(
+ new Columns.All(), new Condition.Equals("email", email)));
+ if (user != null) {
+ var velocityContext = textTemplateFormatter.prepareContext(permissionsService.getServer(), user);
+ var fullMessage = textTemplateFormatter.formatMessage(velocityContext, "passwordReset", "full");
+ mailManager.sendMessage(user, true, fullMessage.getSubject(), fullMessage.getBody());
}
return Response.ok().build();
}
@@ -66,15 +72,18 @@ public class PasswordResource extends BaseResource {
@PermitAll
@POST
public Response update(
- @FormParam("token") String token, @FormParam("password") String password) throws StorageException {
- for (long userId : Context.getUsersManager().getAllItems()) {
- User user = Context.getUsersManager().getById(userId);
- if (token.equals(user.getString(PASSWORD_RESET_TOKEN))) {
- user.getAttributes().remove(PASSWORD_RESET_TOKEN);
- user.setPassword(password);
- Context.getUsersManager().updateItem(user);
- return Response.ok().build();
- }
+ @FormParam("token") String token, @FormParam("password") String password)
+ throws StorageException, GeneralSecurityException, IOException {
+
+ long userId = tokenManager.verifyToken(token);
+ User user = storage.getObject(User.class, new Request(
+ new Columns.All(), new Condition.Equals("id", userId)));
+ if (user != null) {
+ user.setPassword(password);
+ storage.updateObject(user, new Request(
+ new Columns.Include("hashedPassword", "salt"),
+ new Condition.Equals("id", userId)));
+ return Response.ok().build();
}
return Response.status(Response.Status.NOT_FOUND).build();
}
diff --git a/src/main/java/org/traccar/api/resource/PermissionsResource.java b/src/main/java/org/traccar/api/resource/PermissionsResource.java
index 7def38919..e8e4e96eb 100644
--- a/src/main/java/org/traccar/api/resource/PermissionsResource.java
+++ b/src/main/java/org/traccar/api/resource/PermissionsResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,47 +16,40 @@
*/
package org.traccar.api.resource;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Set;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import org.traccar.Context;
import org.traccar.api.BaseResource;
import org.traccar.helper.LogAction;
-import org.traccar.model.Device;
import org.traccar.model.Permission;
-import org.traccar.model.User;
+import org.traccar.model.UserRestrictions;
+import org.traccar.session.cache.CacheManager;
import org.traccar.storage.StorageException;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Set;
+
@Path("permissions")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class PermissionsResource extends BaseResource {
- private void checkPermission(Permission permission, boolean link) {
- if (!link && permission.getOwnerClass().equals(User.class)
- && permission.getPropertyClass().equals(Device.class)) {
- if (getUserId() != permission.getOwnerId()) {
- Context.getPermissionsManager().checkUser(getUserId(), permission.getOwnerId());
- } else {
- Context.getPermissionsManager().checkAdmin(getUserId());
- }
- } else {
- Context.getPermissionsManager().checkPermission(
- permission.getOwnerClass(), getUserId(), permission.getOwnerId());
+ @Inject
+ private CacheManager cacheManager;
+
+ private void checkPermission(Permission permission) throws StorageException {
+ if (permissionsService.notAdmin(getUserId())) {
+ permissionsService.checkPermission(permission.getOwnerClass(), getUserId(), permission.getOwnerId());
+ permissionsService.checkPermission(permission.getPropertyClass(), getUserId(), permission.getPropertyId());
}
- Context.getPermissionsManager().checkPermission(
- permission.getPropertyClass(), getUserId(), permission.getPropertyId());
}
private void checkPermissionTypes(List<LinkedHashMap<String, Long>> entities) {
@@ -72,18 +65,19 @@ public class PermissionsResource extends BaseResource {
@Path("bulk")
@POST
public Response add(List<LinkedHashMap<String, Long>> entities) throws StorageException, ClassNotFoundException {
- Context.getPermissionsManager().checkReadonly(getUserId());
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getReadonly);
checkPermissionTypes(entities);
for (LinkedHashMap<String, Long> entity: entities) {
Permission permission = new Permission(entity);
- checkPermission(permission, true);
- Context.getDataManager().linkObject(permission.getOwnerClass(), permission.getOwnerId(),
- permission.getPropertyClass(), permission.getPropertyId(), true);
- LogAction.link(getUserId(), permission.getOwnerClass(), permission.getOwnerId(),
+ checkPermission(permission);
+ storage.addPermission(permission);
+ cacheManager.invalidatePermission(
+ true,
+ permission.getOwnerClass(), permission.getOwnerId(),
+ permission.getPropertyClass(), permission.getPropertyId());
+ LogAction.link(getUserId(),
+ permission.getOwnerClass(), permission.getOwnerId(),
permission.getPropertyClass(), permission.getPropertyId());
- }
- if (!entities.isEmpty()) {
- Context.getPermissionsManager().refreshPermissions(new Permission(entities.get(0)));
}
return Response.noContent().build();
}
@@ -96,18 +90,19 @@ public class PermissionsResource extends BaseResource {
@DELETE
@Path("bulk")
public Response remove(List<LinkedHashMap<String, Long>> entities) throws StorageException, ClassNotFoundException {
- Context.getPermissionsManager().checkReadonly(getUserId());
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getReadonly);
checkPermissionTypes(entities);
for (LinkedHashMap<String, Long> entity: entities) {
Permission permission = new Permission(entity);
- checkPermission(permission, false);
- Context.getDataManager().linkObject(permission.getOwnerClass(), permission.getOwnerId(),
- permission.getPropertyClass(), permission.getPropertyId(), false);
- LogAction.unlink(getUserId(), permission.getOwnerClass(), permission.getOwnerId(),
+ checkPermission(permission);
+ storage.removePermission(permission);
+ cacheManager.invalidatePermission(
+ true,
+ permission.getOwnerClass(), permission.getOwnerId(),
+ permission.getPropertyClass(), permission.getPropertyId());
+ LogAction.unlink(getUserId(),
+ permission.getOwnerClass(), permission.getOwnerId(),
permission.getPropertyClass(), permission.getPropertyId());
- }
- if (!entities.isEmpty()) {
- Context.getPermissionsManager().refreshPermissions(new Permission(entities.get(0)));
}
return Response.noContent().build();
}
diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java
index 511032402..0d783a0fe 100644
--- a/src/main/java/org/traccar/api/resource/PositionResource.java
+++ b/src/main/java/org/traccar/api/resource/PositionResource.java
@@ -15,52 +15,146 @@
*/
package org.traccar.api.resource;
-import org.traccar.Context;
import org.traccar.api.BaseResource;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Device;
import org.traccar.model.Position;
+import org.traccar.model.UserRestrictions;
+import org.traccar.reports.CsvExportProvider;
+import org.traccar.reports.GpxExportProvider;
+import org.traccar.reports.KmlExportProvider;
import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.StreamingOutput;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.LinkedList;
@Path("positions")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class PositionResource extends BaseResource {
+ @Inject
+ private KmlExportProvider kmlExportProvider;
+
+ @Inject
+ private CsvExportProvider csvExportProvider;
+
+ @Inject
+ private GpxExportProvider gpxExportProvider;
+
@GET
public Collection<Position> getJson(
@QueryParam("deviceId") long deviceId, @QueryParam("id") List<Long> positionIds,
@QueryParam("from") Date from, @QueryParam("to") Date to)
throws StorageException {
if (!positionIds.isEmpty()) {
- ArrayList<Position> positions = new ArrayList<>();
- for (Long positionId : positionIds) {
- Position position = Context.getDataManager().getObject(Position.class, positionId);
- Context.getPermissionsManager().checkDevice(getUserId(), position.getDeviceId());
+ var positions = new ArrayList<Position>();
+ for (long positionId : positionIds) {
+ Position position = storage.getObject(Position.class, new Request(
+ new Columns.All(), new Condition.Equals("id", positionId)));
+ permissionsService.checkPermission(Device.class, getUserId(), position.getDeviceId());
positions.add(position);
}
return positions;
- } else if (deviceId == 0) {
- return Context.getDeviceManager().getInitialState(getUserId());
- } else {
- Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ } else if (deviceId > 0) {
+ permissionsService.checkPermission(Device.class, getUserId(), deviceId);
if (from != null && to != null) {
- Context.getPermissionsManager().checkDisableReports(getUserId());
- return Context.getDataManager().getPositions(deviceId, from, to);
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
+ return PositionUtil.getPositions(storage, deviceId, from, to);
} else {
- return Collections.singleton(Context.getDeviceManager().getLastPosition(deviceId));
+ return storage.getObjects(Position.class, new Request(
+ new Columns.All(), new Condition.LatestPositions(deviceId)));
}
+ } else {
+ return PositionUtil.getLatestPositions(storage, getUserId());
}
}
+ @DELETE
+ public Response remove(
+ @QueryParam("deviceId") long deviceId,
+ @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
+ permissionsService.checkPermission(Device.class, getUserId(), deviceId);
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getReadonly);
+
+ var conditions = new LinkedList<Condition>();
+ conditions.add(new Condition.Equals("deviceId", deviceId));
+ conditions.add(new Condition.Between("fixTime", "from", from, "to", to));
+ storage.removeObject(Position.class, new Request(Condition.merge(conditions)));
+
+ return Response.status(Response.Status.NO_CONTENT).build();
+ }
+
+ @Path("kml")
+ @GET
+ @Produces("application/vnd.google-earth.kml+xml")
+ public Response getKml(
+ @QueryParam("deviceId") long deviceId,
+ @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
+ permissionsService.checkPermission(Device.class, getUserId(), deviceId);
+ StreamingOutput stream = output -> {
+ try {
+ kmlExportProvider.generate(output, deviceId, from, to);
+ } catch (StorageException e) {
+ throw new WebApplicationException(e);
+ }
+ };
+ return Response.ok(stream)
+ .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=positions.kml").build();
+ }
+
+ @Path("csv")
+ @GET
+ @Produces("text/csv")
+ public Response getCsv(
+ @QueryParam("deviceId") long deviceId,
+ @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
+ permissionsService.checkPermission(Device.class, getUserId(), deviceId);
+ StreamingOutput stream = output -> {
+ try {
+ csvExportProvider.generate(output, deviceId, from, to);
+ } catch (StorageException e) {
+ throw new WebApplicationException(e);
+ }
+ };
+ return Response.ok(stream)
+ .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=positions.csv").build();
+ }
+
+ @Path("gpx")
+ @GET
+ @Produces("application/gpx+xml")
+ public Response getGpx(
+ @QueryParam("deviceId") long deviceId,
+ @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
+ permissionsService.checkPermission(Device.class, getUserId(), deviceId);
+ StreamingOutput stream = output -> {
+ try {
+ gpxExportProvider.generate(output, deviceId, from, to);
+ } catch (StorageException e) {
+ throw new WebApplicationException(e);
+ }
+ };
+ return Response.ok(stream)
+ .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=positions.gpx").build();
+ }
+
}
diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java
index 03df0d03a..b4882f219 100644
--- a/src/main/java/org/traccar/api/resource/ReportResource.java
+++ b/src/main/java/org/traccar/api/resource/ReportResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,208 +16,307 @@
*/
package org.traccar.api.resource;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-
-import javax.activation.DataHandler;
-import javax.mail.MessagingException;
-import javax.mail.internet.MimeBodyPart;
-import javax.mail.util.ByteArrayDataSource;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.api.BaseResource;
+import org.traccar.api.SimpleObjectResource;
import org.traccar.helper.LogAction;
import org.traccar.model.Event;
import org.traccar.model.Position;
-import org.traccar.reports.Events;
-import org.traccar.reports.Summary;
-import org.traccar.reports.Trips;
-import org.traccar.reports.model.StopReport;
-import org.traccar.reports.model.SummaryReport;
-import org.traccar.reports.model.TripReport;
-import org.traccar.reports.Route;
-import org.traccar.reports.Stops;
+import org.traccar.model.Report;
+import org.traccar.model.UserRestrictions;
+import org.traccar.reports.CombinedReportProvider;
+import org.traccar.reports.EventsReportProvider;
+import org.traccar.reports.RouteReportProvider;
+import org.traccar.reports.StopsReportProvider;
+import org.traccar.reports.SummaryReportProvider;
+import org.traccar.reports.TripsReportProvider;
+import org.traccar.reports.common.ReportExecutor;
+import org.traccar.reports.common.ReportMailer;
+import org.traccar.reports.model.CombinedReportItem;
+import org.traccar.reports.model.StopReportItem;
+import org.traccar.reports.model.SummaryReportItem;
+import org.traccar.reports.model.TripReportItem;
import org.traccar.storage.StorageException;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.StreamingOutput;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
@Path("reports")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
-public class ReportResource extends BaseResource {
+public class ReportResource extends SimpleObjectResource<Report> {
- private static final Logger LOGGER = LoggerFactory.getLogger(ReportResource.class);
+ private static final String EXCEL = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
- private static final String XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
- private static final String CONTENT_DISPOSITION_VALUE_XLSX = "attachment; filename=report.xlsx";
+ @Inject
+ private CombinedReportProvider combinedReportProvider;
- private interface ReportExecutor {
- void execute(ByteArrayOutputStream stream) throws StorageException, IOException;
- }
+ @Inject
+ private EventsReportProvider eventsReportProvider;
- private Response executeReport(
- long userId, boolean mail, ReportExecutor executor) throws StorageException, IOException {
- final ByteArrayOutputStream stream = new ByteArrayOutputStream();
- if (mail) {
- new Thread(() -> {
- try {
- executor.execute(stream);
+ @Inject
+ private RouteReportProvider routeReportProvider;
- MimeBodyPart attachment = new MimeBodyPart();
+ @Inject
+ private StopsReportProvider stopsReportProvider;
- attachment.setFileName("report.xlsx");
- attachment.setDataHandler(new DataHandler(new ByteArrayDataSource(
- stream.toByteArray(), "application/octet-stream")));
+ @Inject
+ private SummaryReportProvider summaryReportProvider;
- Context.getMailManager().sendMessage(
- userId, "Report", "The report is in the attachment.", attachment);
- } catch (StorageException | IOException | MessagingException e) {
- LOGGER.warn("Report failed", e);
- }
- }).start();
+ @Inject
+ private TripsReportProvider tripsReportProvider;
+
+ @Inject
+ private ReportMailer reportMailer;
+
+ public ReportResource() {
+ super(Report.class);
+ }
+
+ private Response executeReport(long userId, boolean mail, ReportExecutor executor) {
+ if (mail) {
+ reportMailer.sendAsync(userId, executor);
return Response.noContent().build();
} else {
- executor.execute(stream);
- return Response.ok(stream.toByteArray())
- .header(HttpHeaders.CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE_XLSX).build();
+ StreamingOutput stream = output -> {
+ try {
+ executor.execute(output);
+ } catch (StorageException e) {
+ throw new WebApplicationException(e);
+ }
+ };
+ return Response.ok(stream)
+ .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=report.xlsx").build();
}
}
+ @Path("combined")
+ @GET
+ public Collection<CombinedReportItem> getCombined(
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to) throws StorageException {
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
+ LogAction.logReport(getUserId(), "combined", from, to, deviceIds, groupIds);
+ return combinedReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to);
+ }
+
@Path("route")
@GET
public Collection<Position> getRoute(
- @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
- @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to) throws StorageException {
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds);
- return Route.getObjects(getUserId(), deviceIds, groupIds, from, to);
+ return routeReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to);
}
@Path("route")
@GET
- @Produces(XLSX)
+ @Produces(EXCEL)
public Response getRouteExcel(
- @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
- @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail)
- throws StorageException, IOException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to,
+ @QueryParam("mail") boolean mail) throws StorageException {
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds);
- Route.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
+ routeReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
});
}
+ @Path("route/{type:xlsx|mail}")
+ @GET
+ @Produces(EXCEL)
+ public Response getRouteExcel(
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") final List<Long> groupIds,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to,
+ @PathParam("type") String type) throws StorageException {
+ return getRouteExcel(deviceIds, groupIds, from, to, type.equals("mail"));
+ }
+
@Path("events")
@GET
public Collection<Event> getEvents(
- @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
- @QueryParam("type") final List<String> types,
- @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("type") List<String> types,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to) throws StorageException {
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds);
- return Events.getObjects(getUserId(), deviceIds, groupIds, types, from, to);
+ return eventsReportProvider.getObjects(getUserId(), deviceIds, groupIds, types, from, to);
}
@Path("events")
@GET
- @Produces(XLSX)
+ @Produces(EXCEL)
public Response getEventsExcel(
- @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
- @QueryParam("type") final List<String> types,
- @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail)
- throws StorageException, IOException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("type") List<String> types,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to,
+ @QueryParam("mail") boolean mail) throws StorageException {
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds);
- Events.getExcel(stream, getUserId(), deviceIds, groupIds, types, from, to);
+ eventsReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, types, from, to);
});
}
+ @Path("events/{type:xlsx|mail}")
+ @GET
+ @Produces(EXCEL)
+ public Response getEventsExcel(
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("type") List<String> types,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to,
+ @PathParam("type") String type) throws StorageException {
+ return getEventsExcel(deviceIds, groupIds, types, from, to, type.equals("mail"));
+ }
+
@Path("summary")
@GET
- public Collection<SummaryReport> getSummary(
- @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
- @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("daily") boolean daily)
- throws StorageException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ public Collection<SummaryReportItem> getSummary(
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to,
+ @QueryParam("daily") boolean daily) throws StorageException {
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds);
- return Summary.getObjects(getUserId(), deviceIds, groupIds, from, to, daily);
+ return summaryReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to, daily);
}
@Path("summary")
@GET
- @Produces(XLSX)
+ @Produces(EXCEL)
public Response getSummaryExcel(
- @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
- @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("daily") boolean daily,
- @QueryParam("mail") boolean mail)
- throws StorageException, IOException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to,
+ @QueryParam("daily") boolean daily,
+ @QueryParam("mail") boolean mail) throws StorageException {
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds);
- Summary.getExcel(stream, getUserId(), deviceIds, groupIds, from, to, daily);
+ summaryReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to, daily);
});
}
+ @Path("summary/{type:xlsx|mail}")
+ @GET
+ @Produces(EXCEL)
+ public Response getSummaryExcel(
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to,
+ @QueryParam("daily") boolean daily,
+ @PathParam("type") String type) throws StorageException {
+ return getSummaryExcel(deviceIds, groupIds, from, to, daily, type.equals("mail"));
+ }
+
@Path("trips")
@GET
- @Produces(MediaType.APPLICATION_JSON)
- public Collection<TripReport> getTrips(
- @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
- @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ public Collection<TripReportItem> getTrips(
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to) throws StorageException {
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds);
- return Trips.getObjects(getUserId(), deviceIds, groupIds, from, to);
+ return tripsReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to);
}
@Path("trips")
@GET
- @Produces(XLSX)
+ @Produces(EXCEL)
public Response getTripsExcel(
- @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
- @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail)
- throws StorageException, IOException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to,
+ @QueryParam("mail") boolean mail) throws StorageException {
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds);
- Trips.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
+ tripsReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
});
}
+ @Path("trips/{type:xlsx|mail}")
+ @GET
+ @Produces(EXCEL)
+ public Response getTripsExcel(
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to,
+ @PathParam("type") String type) throws StorageException {
+ return getTripsExcel(deviceIds, groupIds, from, to, type.equals("mail"));
+ }
+
@Path("stops")
@GET
- @Produces(MediaType.APPLICATION_JSON)
- public Collection<StopReport> getStops(
- @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
- @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ public Collection<StopReportItem> getStops(
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to) throws StorageException {
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds);
- return Stops.getObjects(getUserId(), deviceIds, groupIds, from, to);
+ return stopsReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to);
}
@Path("stops")
@GET
- @Produces(XLSX)
+ @Produces(EXCEL)
public Response getStopsExcel(
- @QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
- @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail)
- throws StorageException, IOException {
- Context.getPermissionsManager().checkDisableReports(getUserId());
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to,
+ @QueryParam("mail") boolean mail) throws StorageException {
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds);
- Stops.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
+ stopsReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
});
}
+ @Path("stops/{type:xlsx|mail}")
+ @GET
+ @Produces(EXCEL)
+ public Response getStopsExcel(
+ @QueryParam("deviceId") List<Long> deviceIds,
+ @QueryParam("groupId") List<Long> groupIds,
+ @QueryParam("from") Date from,
+ @QueryParam("to") Date to,
+ @PathParam("type") String type) throws StorageException {
+ return getStopsExcel(deviceIds, groupIds, from, to, type.equals("mail"));
+ }
+
}
diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java
index 2d17d5e47..8149ec3b8 100644
--- a/src/main/java/org/traccar/api/resource/ServerResource.java
+++ b/src/main/java/org/traccar/api/resource/ServerResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,25 +15,46 @@
*/
package org.traccar.api.resource;
-import org.traccar.Context;
import org.traccar.api.BaseResource;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.database.OpenIdProvider;
+import org.traccar.geocoder.Geocoder;
+import org.traccar.helper.Log;
import org.traccar.helper.LogAction;
+import org.traccar.helper.model.UserUtil;
+import org.traccar.mail.MailManager;
import org.traccar.model.Server;
-import org.traccar.storage.Storage;
+import org.traccar.model.User;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.sms.SmsManager;
import org.traccar.storage.StorageException;
import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
import org.traccar.storage.query.Request;
-import javax.annotation.security.PermitAll;
-import javax.inject.Inject;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
+import jakarta.annotation.Nullable;
+import jakarta.annotation.security.PermitAll;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.TimeZone;
@Path("server")
@Produces(MediaType.APPLICATION_JSON)
@@ -41,18 +62,56 @@ import javax.ws.rs.core.Response;
public class ServerResource extends BaseResource {
@Inject
- private Storage storage;
+ private Config config;
+
+ @Inject
+ private CacheManager cacheManager;
+
+ @Inject
+ private MailManager mailManager;
+
+ @Inject
+ @Nullable
+ private SmsManager smsManager;
+
+ @Inject
+ @Nullable
+ private OpenIdProvider openIdProvider;
+
+ @Inject
+ @Nullable
+ private Geocoder geocoder;
@PermitAll
@GET
public Server get() throws StorageException {
- return storage.getObject(Server.class, new Request(new Columns.All()));
+ Server server = storage.getObject(Server.class, new Request(new Columns.All()));
+ server.setEmailEnabled(mailManager.getEmailEnabled());
+ server.setTextEnabled(smsManager != null);
+ server.setGeocoderEnabled(geocoder != null);
+ server.setOpenIdEnabled(openIdProvider != null);
+ server.setOpenIdForce(openIdProvider != null && openIdProvider.getForce());
+ User user = permissionsService.getUser(getUserId());
+ if (user != null) {
+ if (user.getAdministrator()) {
+ server.setStorageSpace(Log.getStorageSpace());
+ }
+ } else {
+ server.setNewServer(UserUtil.isEmpty(storage));
+ }
+ if (user != null && user.getAdministrator()) {
+ server.setStorageSpace(Log.getStorageSpace());
+ }
+ return server;
}
@PUT
public Response update(Server entity) throws StorageException {
- Context.getPermissionsManager().checkAdmin(getUserId());
- Context.getPermissionsManager().updateServer(entity);
+ permissionsService.checkAdmin(getUserId());
+ storage.updateObject(entity, new Request(
+ new Columns.Exclude("id"),
+ new Condition.Equals("id", entity.getId())));
+ cacheManager.updateOrInvalidate(true, entity);
LogAction.edit(getUserId(), entity);
return Response.ok(entity).build();
}
@@ -60,11 +119,36 @@ public class ServerResource extends BaseResource {
@Path("geocode")
@GET
public String geocode(@QueryParam("latitude") double latitude, @QueryParam("longitude") double longitude) {
- if (Context.getGeocoder() != null) {
- return Context.getGeocoder().getAddress(latitude, longitude, null);
+ if (geocoder != null) {
+ return geocoder.getAddress(latitude, longitude, null);
} else {
throw new RuntimeException("Reverse geocoding is not enabled");
}
}
+ @Path("timezones")
+ @GET
+ public Collection<String> timezones() {
+ return Arrays.asList(TimeZone.getAvailableIDs());
+ }
+
+ @Path("file/{path}")
+ @POST
+ @Consumes("*/*")
+ public Response uploadImage(@PathParam("path") String path, File inputFile) throws IOException, StorageException {
+ permissionsService.checkAdmin(getUserId());
+ String root = config.getString(Keys.WEB_OVERRIDE, config.getString(Keys.WEB_PATH));
+
+ var outputPath = Paths.get(root, path);
+ var directoryPath = outputPath.getParent();
+ if (directoryPath != null) {
+ Files.createDirectories(directoryPath);
+ }
+
+ try (var input = new FileInputStream(inputFile); var output = new FileOutputStream(outputPath.toFile())) {
+ input.transferTo(output);
+ }
+ return Response.ok().build();
+ }
+
}
diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java
index 8422e0b49..3e738c15a 100644
--- a/src/main/java/org/traccar/api/resource/SessionResource.java
+++ b/src/main/java/org/traccar/api/resource/SessionResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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,32 +15,44 @@
*/
package org.traccar.api.resource;
-import org.traccar.Context;
import org.traccar.api.BaseResource;
+import org.traccar.api.security.LoginService;
+import org.traccar.api.signature.TokenManager;
+import org.traccar.database.OpenIdProvider;
import org.traccar.helper.DataConverter;
-import org.traccar.helper.ServletHelper;
import org.traccar.helper.LogAction;
+import org.traccar.helper.WebHelper;
import org.traccar.model.User;
import org.traccar.storage.StorageException;
-
-import javax.annotation.security.PermitAll;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.FormParam;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import java.io.UnsupportedEncodingException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import com.nimbusds.oauth2.sdk.ParseException;
+import jakarta.annotation.Nullable;
+import jakarta.annotation.security.PermitAll;
+import jakarta.inject.Inject;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.FormParam;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.util.Date;
+import java.net.URI;
@Path("session")
@Produces(MediaType.APPLICATION_JSON)
@@ -51,18 +63,28 @@ public class SessionResource extends BaseResource {
public static final String USER_COOKIE_KEY = "user";
public static final String PASS_COOKIE_KEY = "password";
- @javax.ws.rs.core.Context
+ @Inject
+ private LoginService loginService;
+
+ @Inject
+ @Nullable
+ private OpenIdProvider openIdProvider;
+
+ @Inject
+ private TokenManager tokenManager;
+
+ @Context
private HttpServletRequest request;
@PermitAll
@GET
- public User get(@QueryParam("token") String token) throws StorageException, UnsupportedEncodingException {
+ public User get(@QueryParam("token") String token) throws StorageException, IOException, GeneralSecurityException {
if (token != null) {
- User user = Context.getUsersManager().getUserByToken(token);
+ User user = loginService.login(token);
if (user != null) {
- Context.getPermissionsManager().checkUserEnabled(user.getId());
request.getSession().setAttribute(USER_ID_KEY, user.getId());
+ LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request));
return user;
}
}
@@ -76,54 +98,91 @@ public class SessionResource extends BaseResource {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(USER_COOKIE_KEY)) {
byte[] emailBytes = DataConverter.parseBase64(
- URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII.name()));
+ URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII));
email = new String(emailBytes, StandardCharsets.UTF_8);
} else if (cookie.getName().equals(PASS_COOKIE_KEY)) {
byte[] passwordBytes = DataConverter.parseBase64(
- URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII.name()));
+ URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII));
password = new String(passwordBytes, StandardCharsets.UTF_8);
}
}
}
if (email != null && password != null) {
- User user = Context.getPermissionsManager().login(email, password);
+ User user = loginService.login(email, password);
if (user != null) {
- Context.getPermissionsManager().checkUserEnabled(user.getId());
request.getSession().setAttribute(USER_ID_KEY, user.getId());
+ LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request));
return user;
}
}
} else {
- Context.getPermissionsManager().checkUserEnabled(userId);
- return Context.getPermissionsManager().getUser(userId);
+ User user = permissionsService.getUser(userId);
+ if (user != null) {
+ return user;
+ }
}
throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
}
+ @Path("{id}")
+ @GET
+ public User get(@PathParam("id") long userId) throws StorageException {
+ permissionsService.checkUser(getUserId(), userId);
+ User user = storage.getObject(User.class, new Request(
+ new Columns.All(), new Condition.Equals("id", userId)));
+ request.getSession().setAttribute(USER_ID_KEY, user.getId());
+ LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request));
+ return user;
+ }
+
@PermitAll
@POST
public User add(
@FormParam("email") String email, @FormParam("password") String password) throws StorageException {
- User user = Context.getPermissionsManager().login(email, password);
+ User user = loginService.login(email, password);
if (user != null) {
request.getSession().setAttribute(USER_ID_KEY, user.getId());
- LogAction.login(user.getId());
+ LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request));
return user;
} else {
- LogAction.failedLogin(ServletHelper.retrieveRemoteAddress(request));
+ LogAction.failedLogin(WebHelper.retrieveRemoteAddress(request));
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build());
}
}
@DELETE
public Response remove() {
- LogAction.logout(getUserId());
+ LogAction.logout(getUserId(), WebHelper.retrieveRemoteAddress(request));
request.getSession().removeAttribute(USER_ID_KEY);
return Response.noContent().build();
}
+ @Path("token")
+ @POST
+ public String requestToken(
+ @FormParam("expiration") Date expiration) throws StorageException, GeneralSecurityException, IOException {
+ return tokenManager.generateToken(getUserId(), expiration);
+ }
+
+ @PermitAll
+ @Path("openid/auth")
+ @GET
+ public Response openIdAuth() throws IOException {
+ return Response.seeOther(openIdProvider.createAuthUri()).build();
+ }
+
+ @PermitAll
+ @Path("openid/callback")
+ @GET
+ public Response requestToken() throws IOException, StorageException, ParseException, GeneralSecurityException {
+ StringBuilder requestUrl = new StringBuilder(request.getRequestURL().toString());
+ String queryString = request.getQueryString();
+ String requestUri = requestUrl.append('?').append(queryString).toString();
+
+ return Response.seeOther(openIdProvider.handleCallback(URI.create(requestUri), request)).build();
+ }
}
diff --git a/src/main/java/org/traccar/api/resource/StatisticsResource.java b/src/main/java/org/traccar/api/resource/StatisticsResource.java
index 5c0734877..0c728c77d 100644
--- a/src/main/java/org/traccar/api/resource/StatisticsResource.java
+++ b/src/main/java/org/traccar/api/resource/StatisticsResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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,17 +15,20 @@
*/
package org.traccar.api.resource;
-import org.traccar.Context;
import org.traccar.api.BaseResource;
import org.traccar.model.Statistics;
import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Order;
+import org.traccar.storage.query.Request;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.MediaType;
import java.util.Collection;
import java.util.Date;
@@ -37,8 +40,11 @@ public class StatisticsResource extends BaseResource {
@GET
public Collection<Statistics> get(
@QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
- Context.getPermissionsManager().checkAdmin(getUserId());
- return Context.getDataManager().getStatistics(from, to);
+ permissionsService.checkAdmin(getUserId());
+ return storage.getObjects(Statistics.class, new Request(
+ new Columns.All(),
+ new Condition.Between("captureTime", "from", from, "to", to),
+ new Order("captureTime")));
}
}
diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java
index 83bb8fd0b..cbee3bd4a 100644
--- a/src/main/java/org/traccar/api/resource/UserResource.java
+++ b/src/main/java/org/traccar/api/resource/UserResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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,81 +15,99 @@
*/
package org.traccar.api.resource;
-import org.traccar.Context;
import org.traccar.api.BaseObjectResource;
-import org.traccar.config.Keys;
-import org.traccar.database.UsersManager;
+import org.traccar.config.Config;
import org.traccar.helper.LogAction;
+import org.traccar.helper.model.UserUtil;
import org.traccar.model.ManagedUser;
+import org.traccar.model.Permission;
import org.traccar.model.User;
import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
-import javax.annotation.security.PermitAll;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.sql.SQLException;
+import jakarta.annotation.security.PermitAll;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
import java.util.Collection;
-import java.util.Date;
-import java.util.Set;
@Path("users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserResource extends BaseObjectResource<User> {
+ @Inject
+ private Config config;
+
public UserResource() {
super(User.class);
}
@GET
- public Collection<User> get(@QueryParam("userId") long userId) throws SQLException {
- UsersManager usersManager = Context.getUsersManager();
- Set<Long> result;
- if (Context.getPermissionsManager().getUserAdmin(getUserId())) {
- if (userId != 0) {
- result = usersManager.getUserItems(userId);
- } else {
- result = usersManager.getAllItems();
- }
- } else if (Context.getPermissionsManager().getUserManager(getUserId())) {
- result = usersManager.getManagedItems(getUserId());
+ public Collection<User> get(@QueryParam("userId") long userId) throws StorageException {
+ if (userId > 0) {
+ permissionsService.checkUser(getUserId(), userId);
+ return storage.getObjects(baseClass, new Request(
+ new Columns.All(),
+ new Condition.Permission(User.class, userId, ManagedUser.class).excludeGroups()));
+ } else if (permissionsService.notAdmin(getUserId())) {
+ return storage.getObjects(baseClass, new Request(
+ new Columns.All(),
+ new Condition.Permission(User.class, getUserId(), ManagedUser.class).excludeGroups()));
} else {
- throw new SecurityException("Admin or manager access required");
+ return storage.getObjects(baseClass, new Request(new Columns.All()));
}
- return usersManager.getItems(result);
}
@Override
@PermitAll
@POST
public Response add(User entity) throws StorageException {
- if (!Context.getPermissionsManager().getUserAdmin(getUserId())) {
- Context.getPermissionsManager().checkUserUpdate(getUserId(), new User(), entity);
- if (Context.getPermissionsManager().getUserManager(getUserId())) {
- Context.getPermissionsManager().checkUserLimit(getUserId());
+ User currentUser = getUserId() > 0 ? permissionsService.getUser(getUserId()) : null;
+ if (currentUser == null || !currentUser.getAdministrator()) {
+ permissionsService.checkUserUpdate(getUserId(), new User(), entity);
+ if (currentUser != null && currentUser.getUserLimit() != 0) {
+ int userLimit = currentUser.getUserLimit();
+ if (userLimit > 0) {
+ int userCount = storage.getObjects(baseClass, new Request(
+ new Columns.All(),
+ new Condition.Permission(User.class, getUserId(), ManagedUser.class).excludeGroups()))
+ .size();
+ if (userCount >= userLimit) {
+ throw new SecurityException("Manager user limit reached");
+ }
+ }
} else {
- Context.getPermissionsManager().checkRegistration(getUserId());
- entity.setDeviceLimit(Context.getConfig().getInteger(Keys.USERS_DEFAULT_DEVICE_LIMIT));
- int expirationDays = Context.getConfig().getInteger(Keys.USERS_DEFAULT_EXPIRATION_DAYS);
- if (expirationDays > 0) {
- entity.setExpirationTime(
- new Date(System.currentTimeMillis() + (long) expirationDays * 24 * 3600 * 1000));
+ if (!permissionsService.getServer().getRegistration()) {
+ throw new SecurityException("Registration disabled");
}
+ UserUtil.setUserDefaults(entity, config);
}
}
- Context.getUsersManager().addItem(entity);
+
+ if (UserUtil.isEmpty(storage)) {
+ entity.setAdministrator(true);
+ }
+
+ entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id"))));
+ storage.updateObject(entity, new Request(
+ new Columns.Include("hashedPassword", "salt"),
+ new Condition.Equals("id", entity.getId())));
+
LogAction.create(getUserId(), entity);
- if (Context.getPermissionsManager().getUserManager(getUserId())) {
- Context.getDataManager().linkObject(User.class, getUserId(), ManagedUser.class, entity.getId(), true);
+
+ if (currentUser != null && currentUser.getUserLimit() != 0) {
+ storage.addPermission(new Permission(User.class, getUserId(), ManagedUser.class, entity.getId()));
LogAction.link(getUserId(), User.class, getUserId(), ManagedUser.class, entity.getId());
}
- Context.getUsersManager().refreshUserItems();
return Response.ok(entity).build();
}
diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java
new file mode 100644
index 000000000..91e964ee9
--- /dev/null
+++ b/src/main/java/org/traccar/api/security/LoginService.java
@@ -0,0 +1,129 @@
+/*
+ * 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.api.security;
+
+import org.traccar.api.signature.TokenManager;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.database.LdapProvider;
+import org.traccar.helper.model.UserUtil;
+import org.traccar.model.User;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.annotation.Nullable;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+@Singleton
+public class LoginService {
+
+ private final Config config;
+ private final Storage storage;
+ private final TokenManager tokenManager;
+ private final LdapProvider ldapProvider;
+
+ private final String serviceAccountToken;
+ private final boolean forceLdap;
+ private final boolean forceOpenId;
+
+ @Inject
+ public LoginService(
+ Config config, Storage storage, TokenManager tokenManager, @Nullable LdapProvider ldapProvider) {
+ this.storage = storage;
+ this.config = config;
+ this.tokenManager = tokenManager;
+ this.ldapProvider = ldapProvider;
+ serviceAccountToken = config.getString(Keys.WEB_SERVICE_ACCOUNT_TOKEN);
+ forceLdap = config.getBoolean(Keys.LDAP_FORCE);
+ forceOpenId = config.getBoolean(Keys.OPENID_FORCE);
+ }
+
+ public User login(String token) throws StorageException, GeneralSecurityException, IOException {
+ if (serviceAccountToken != null && serviceAccountToken.equals(token)) {
+ return new ServiceAccountUser();
+ }
+ long userId = tokenManager.verifyToken(token);
+ User user = storage.getObject(User.class, new Request(
+ new Columns.All(), new Condition.Equals("id", userId)));
+ if (user != null) {
+ checkUserEnabled(user);
+ }
+ return user;
+ }
+
+ public User login(String email, String password) throws StorageException {
+ if (forceOpenId) {
+ return null;
+ }
+
+ email = email.trim();
+ User user = storage.getObject(User.class, new Request(
+ new Columns.All(),
+ new Condition.Or(
+ new Condition.Equals("email", email),
+ new Condition.Equals("login", email))));
+ if (user != null) {
+ if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password)
+ || !forceLdap && user.isPasswordValid(password)) {
+ checkUserEnabled(user);
+ return user;
+ }
+ } else {
+ if (ldapProvider != null && ldapProvider.login(email, password)) {
+ user = ldapProvider.getUser(email);
+ user.setId(storage.addObject(user, new Request(new Columns.Exclude("id"))));
+ checkUserEnabled(user);
+ return user;
+ }
+ }
+ return null;
+ }
+
+ public User login(String email, String name, Boolean administrator) throws StorageException {
+ User user = storage.getObject(User.class, new Request(
+ new Columns.All(),
+ new Condition.Equals("email", email)));
+
+ if (user != null) {
+ checkUserEnabled(user);
+ return user;
+ } else {
+ user = new User();
+ UserUtil.setUserDefaults(user, config);
+ user.setName(name);
+ user.setEmail(email);
+ user.setFixedEmail(true);
+ user.setAdministrator(administrator);
+ user.setId(storage.addObject(user, new Request(new Columns.Exclude("id"))));
+ checkUserEnabled(user);
+ return user;
+ }
+ }
+
+ private void checkUserEnabled(User user) throws SecurityException {
+ if (user == null) {
+ throw new SecurityException("Unknown account");
+ }
+ user.checkDisabled();
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java
new file mode 100644
index 000000000..d60bbafb8
--- /dev/null
+++ b/src/main/java/org/traccar/api/security/PermissionsService.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2022 - 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.api.security;
+
+import com.google.inject.servlet.RequestScoped;
+import org.traccar.model.BaseModel;
+import org.traccar.model.Calendar;
+import org.traccar.model.Command;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.model.GroupedModel;
+import org.traccar.model.ManagedUser;
+import org.traccar.model.Notification;
+import org.traccar.model.Schedulable;
+import org.traccar.model.Server;
+import org.traccar.model.User;
+import org.traccar.model.UserRestrictions;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import java.util.Objects;
+
+@RequestScoped
+public class PermissionsService {
+
+ private final Storage storage;
+
+ private Server server;
+ private User user;
+
+ @Inject
+ public PermissionsService(Storage storage) {
+ this.storage = storage;
+ }
+
+ public Server getServer() throws StorageException {
+ if (server == null) {
+ server = storage.getObject(
+ Server.class, new Request(new Columns.All()));
+ }
+ return server;
+ }
+
+ public User getUser(long userId) throws StorageException {
+ if (user == null && userId > 0) {
+ if (userId == ServiceAccountUser.ID) {
+ user = new ServiceAccountUser();
+ } else {
+ user = storage.getObject(
+ User.class, new Request(new Columns.All(), new Condition.Equals("id", userId)));
+ }
+ }
+ return user;
+ }
+
+ public boolean notAdmin(long userId) throws StorageException {
+ return !getUser(userId).getAdministrator();
+ }
+
+ public void checkAdmin(long userId) throws StorageException, SecurityException {
+ if (!getUser(userId).getAdministrator()) {
+ throw new SecurityException("Administrator access required");
+ }
+ }
+
+ public void checkManager(long userId) throws StorageException, SecurityException {
+ if (!getUser(userId).getAdministrator() && getUser(userId).getUserLimit() == 0) {
+ throw new SecurityException("Manager access required");
+ }
+ }
+
+ public interface CheckRestrictionCallback {
+ boolean denied(UserRestrictions userRestrictions);
+ }
+
+ public void checkRestriction(
+ long userId, CheckRestrictionCallback callback) throws StorageException, SecurityException {
+ if (!getUser(userId).getAdministrator()
+ && (callback.denied(getServer()) || callback.denied(getUser(userId)))) {
+ throw new SecurityException("Operation restricted");
+ }
+ }
+
+ public void checkEdit(long userId, Class<?> clazz, boolean addition) throws StorageException, SecurityException {
+ if (!getUser(userId).getAdministrator()) {
+ boolean denied = false;
+ if (getServer().getReadonly() || getUser(userId).getReadonly()) {
+ denied = true;
+ } else if (clazz.equals(Device.class)) {
+ denied = getServer().getDeviceReadonly() || getUser(userId).getDeviceReadonly()
+ || addition && getUser(userId).getDeviceLimit() == 0;
+ if (!denied && addition && getUser(userId).getDeviceLimit() > 0) {
+ int deviceCount = storage.getObjects(Device.class, new Request(
+ new Columns.Include("id"),
+ new Condition.Permission(User.class, userId, Device.class))).size();
+ denied = deviceCount >= getUser(userId).getDeviceLimit();
+ }
+ } else if (clazz.equals(Command.class)) {
+ denied = getServer().getLimitCommands() || getUser(userId).getLimitCommands();
+ }
+ if (denied) {
+ throw new SecurityException("Write access denied");
+ }
+ }
+ }
+
+ public void checkEdit(long userId, BaseModel object, boolean addition) throws StorageException, SecurityException {
+ if (!getUser(userId).getAdministrator()) {
+ checkEdit(userId, object.getClass(), addition);
+ if (object instanceof GroupedModel) {
+ GroupedModel after = ((GroupedModel) object);
+ if (after.getGroupId() > 0) {
+ GroupedModel before = null;
+ if (!addition) {
+ before = storage.getObject(after.getClass(), new Request(
+ new Columns.Include("groupId"), new Condition.Equals("id", after.getId())));
+ }
+ if (before == null || before.getGroupId() != after.getGroupId()) {
+ checkPermission(Group.class, userId, after.getGroupId());
+ }
+ }
+ }
+ if (object instanceof Schedulable) {
+ Schedulable after = ((Schedulable) object);
+ if (after.getCalendarId() > 0) {
+ Schedulable before = null;
+ if (!addition) {
+ before = storage.getObject(after.getClass(), new Request(
+ new Columns.Include("calendarId"), new Condition.Equals("id", object.getId())));
+ }
+ if (before == null || before.getCalendarId() != after.getCalendarId()) {
+ checkPermission(Calendar.class, userId, after.getCalendarId());
+ }
+ }
+ }
+ if (object instanceof Notification) {
+ Notification after = ((Notification) object);
+ if (after.getCommandId() > 0) {
+ Notification before = null;
+ if (!addition) {
+ before = storage.getObject(after.getClass(), new Request(
+ new Columns.Include("commandId"), new Condition.Equals("id", object.getId())));
+ }
+ if (before == null || before.getCommandId() != after.getCommandId()) {
+ checkPermission(Command.class, userId, after.getCommandId());
+ }
+ }
+ }
+ }
+ }
+
+ public void checkUser(long userId, long managedUserId) throws StorageException, SecurityException {
+ if (userId != managedUserId && !getUser(userId).getAdministrator()) {
+ if (!getUser(userId).getManager()
+ || storage.getPermissions(User.class, userId, ManagedUser.class, managedUserId).isEmpty()) {
+ throw new SecurityException("User access denied");
+ }
+ }
+ }
+
+ public void checkUserUpdate(long userId, User before, User after) throws StorageException, SecurityException {
+ if (before.getAdministrator() != after.getAdministrator()
+ || before.getDeviceLimit() != after.getDeviceLimit()
+ || before.getUserLimit() != after.getUserLimit()) {
+ checkAdmin(userId);
+ }
+ User user = userId > 0 ? getUser(userId) : null;
+ if (user != null && user.getExpirationTime() != null
+ && !Objects.equals(before.getExpirationTime(), after.getExpirationTime())
+ && (after.getExpirationTime() == null
+ || user.getExpirationTime().compareTo(after.getExpirationTime()) < 0)) {
+ checkAdmin(userId);
+ }
+ if (before.getReadonly() != after.getReadonly()
+ || before.getDeviceReadonly() != after.getDeviceReadonly()
+ || before.getDisabled() != after.getDisabled()
+ || before.getLimitCommands() != after.getLimitCommands()
+ || before.getDisableReports() != after.getDisableReports()
+ || before.getFixedEmail() != after.getFixedEmail()) {
+ if (userId == after.getId()) {
+ checkAdmin(userId);
+ } else if (after.getId() > 0) {
+ checkUser(userId, after.getId());
+ } else {
+ checkManager(userId);
+ }
+ }
+ if (before.getFixedEmail() && !before.getEmail().equals(after.getEmail())) {
+ checkAdmin(userId);
+ }
+ }
+
+ public <T extends BaseModel> void checkPermission(
+ Class<T> clazz, long userId, long objectId) throws StorageException, SecurityException {
+ if (!getUser(userId).getAdministrator() && !(clazz.equals(User.class) && userId == objectId)) {
+ var object = storage.getObject(clazz, new Request(
+ new Columns.Include("id"),
+ new Condition.And(
+ new Condition.Equals("id", objectId),
+ new Condition.Permission(
+ User.class, userId, clazz.equals(User.class) ? ManagedUser.class : clazz))));
+ if (object == null) {
+ throw new SecurityException(clazz.getSimpleName() + " access denied");
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java
index 9f20acb40..a34361854 100644
--- a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java
+++ b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,37 +15,34 @@
*/
package org.traccar.api.security;
+import com.google.inject.Injector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.Main;
import org.traccar.api.resource.SessionResource;
import org.traccar.database.StatisticsManager;
import org.traccar.helper.DataConverter;
import org.traccar.model.User;
import org.traccar.storage.StorageException;
-import javax.annotation.security.PermitAll;
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.container.ContainerRequestContext;
-import javax.ws.rs.container.ContainerRequestFilter;
-import javax.ws.rs.container.ResourceInfo;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.SecurityContext;
+import jakarta.annotation.security.PermitAll;
+import jakarta.inject.Inject;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerRequestFilter;
+import jakarta.ws.rs.container.ResourceInfo;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.SecurityContext;
+import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
public class SecurityRequestFilter implements ContainerRequestFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(SecurityRequestFilter.class);
- public static final String AUTHORIZATION_HEADER = "Authorization";
- public static final String WWW_AUTHENTICATE = "WWW-Authenticate";
- public static final String BASIC_REALM = "Basic realm=\"api\"";
- public static final String X_REQUESTED_WITH = "X-Requested-With";
- public static final String XML_HTTP_REQUEST = "XMLHttpRequest";
-
public static String[] decodeBasicAuth(String auth) {
auth = auth.replaceFirst("[B|b]asic ", "");
byte[] decodedBytes = DataConverter.parseBase64(auth);
@@ -55,12 +52,21 @@ public class SecurityRequestFilter implements ContainerRequestFilter {
return null;
}
- @javax.ws.rs.core.Context
+ @Context
private HttpServletRequest request;
- @javax.ws.rs.core.Context
+ @Context
private ResourceInfo resourceInfo;
+ @Inject
+ private LoginService loginService;
+
+ @Inject
+ private StatisticsManager statisticsManager;
+
+ @Inject
+ private Injector injector;
+
@Override
public void filter(ContainerRequestContext requestContext) {
@@ -72,17 +78,22 @@ public class SecurityRequestFilter implements ContainerRequestFilter {
try {
- String authHeader = requestContext.getHeaderString(AUTHORIZATION_HEADER);
+ String authHeader = requestContext.getHeaderString("Authorization");
if (authHeader != null) {
try {
- String[] auth = decodeBasicAuth(authHeader);
- User user = Context.getPermissionsManager().login(auth[0], auth[1]);
+ User user;
+ if (authHeader.startsWith("Bearer ")) {
+ user = loginService.login(authHeader.substring(7));
+ } else {
+ String[] auth = decodeBasicAuth(authHeader);
+ user = loginService.login(auth[0], auth[1]);
+ }
if (user != null) {
- Main.getInjector().getInstance(StatisticsManager.class).registerRequest(user.getId());
+ statisticsManager.registerRequest(user.getId());
securityContext = new UserSecurityContext(new UserPrincipal(user.getId()));
}
- } catch (StorageException e) {
+ } catch (StorageException | GeneralSecurityException | IOException e) {
throw new WebApplicationException(e);
}
@@ -90,14 +101,14 @@ public class SecurityRequestFilter implements ContainerRequestFilter {
Long userId = (Long) request.getSession().getAttribute(SessionResource.USER_ID_KEY);
if (userId != null) {
- Context.getPermissionsManager().checkUserEnabled(userId);
- Main.getInjector().getInstance(StatisticsManager.class).registerRequest(userId);
+ injector.getInstance(PermissionsService.class).getUser(userId).checkDisabled();
+ statisticsManager.registerRequest(userId);
securityContext = new UserSecurityContext(new UserPrincipal(userId));
}
}
- } catch (SecurityException e) {
+ } catch (SecurityException | StorageException e) {
LOGGER.warn("Authentication error", e);
}
@@ -107,8 +118,9 @@ public class SecurityRequestFilter implements ContainerRequestFilter {
Method method = resourceInfo.getResourceMethod();
if (!method.isAnnotationPresent(PermitAll.class)) {
Response.ResponseBuilder responseBuilder = Response.status(Response.Status.UNAUTHORIZED);
- if (!XML_HTTP_REQUEST.equals(request.getHeader(X_REQUESTED_WITH))) {
- responseBuilder.header(WWW_AUTHENTICATE, BASIC_REALM);
+ String accept = request.getHeader("Accept");
+ if (accept != null && accept.contains("text/html")) {
+ responseBuilder.header("WWW-Authenticate", "Basic realm=\"api\"");
}
throw new WebApplicationException(responseBuilder.build());
}
diff --git a/src/main/java/org/traccar/database/MaintenancesManager.java b/src/main/java/org/traccar/api/security/ServiceAccountUser.java
index 4e266cb78..644142434 100644
--- a/src/main/java/org/traccar/database/MaintenancesManager.java
+++ b/src/main/java/org/traccar/api/security/ServiceAccountUser.java
@@ -1,6 +1,5 @@
/*
- * Copyright 2018 Anton Tananaev (anton@traccar.org)
- * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
+ * 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.
@@ -14,14 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.database;
+package org.traccar.api.security;
-import org.traccar.model.Maintenance;
+import org.traccar.model.User;
-public class MaintenancesManager extends ExtendedObjectManager<Maintenance> {
+public class ServiceAccountUser extends User {
- public MaintenancesManager(DataManager dataManager) {
- super(dataManager, Maintenance.class);
- }
+ public static final long ID = 9000000000000000000L;
+ public ServiceAccountUser() {
+ setId(ID);
+ setName("Service Account");
+ setEmail("none");
+ setAdministrator(true);
+ }
}
diff --git a/src/main/java/org/traccar/api/security/UserSecurityContext.java b/src/main/java/org/traccar/api/security/UserSecurityContext.java
index 97df6b6c7..f7adeac64 100644
--- a/src/main/java/org/traccar/api/security/UserSecurityContext.java
+++ b/src/main/java/org/traccar/api/security/UserSecurityContext.java
@@ -15,7 +15,7 @@
*/
package org.traccar.api.security;
-import javax.ws.rs.core.SecurityContext;
+import jakarta.ws.rs.core.SecurityContext;
import java.security.Principal;
public class UserSecurityContext implements SecurityContext {
diff --git a/src/main/java/org/traccar/api/signature/CryptoManager.java b/src/main/java/org/traccar/api/signature/CryptoManager.java
new file mode 100644
index 000000000..71f56e0fb
--- /dev/null
+++ b/src/main/java/org/traccar/api/signature/CryptoManager.java
@@ -0,0 +1,103 @@
+/*
+ * 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.api.signature;
+
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+@Singleton
+public class CryptoManager {
+
+ private final Storage storage;
+
+ private PublicKey publicKey;
+ private PrivateKey privateKey;
+
+ @Inject
+ public CryptoManager(Storage storage) {
+ this.storage = storage;
+ }
+
+ public byte[] sign(byte[] data) throws GeneralSecurityException, StorageException {
+ if (privateKey == null) {
+ initializeKeys();
+ }
+ Signature signature = Signature.getInstance("SHA256withECDSA");
+ signature.initSign(privateKey);
+ signature.update(data);
+ byte[] block = signature.sign();
+ byte[] combined = new byte[1 + block.length + data.length];
+ combined[0] = (byte) block.length;
+ System.arraycopy(block, 0, combined, 1, block.length);
+ System.arraycopy(data, 0, combined, 1 + block.length, data.length);
+ return combined;
+ }
+
+ public byte[] verify(byte[] data) throws GeneralSecurityException, StorageException {
+ if (publicKey == null) {
+ initializeKeys();
+ }
+ Signature signature = Signature.getInstance("SHA256withECDSA");
+ signature.initVerify(publicKey);
+ int length = data[0];
+ byte[] originalData = new byte[data.length - 1 - length];
+ System.arraycopy(data, 1 + length, originalData, 0, originalData.length);
+ signature.update(originalData);
+ if (!signature.verify(data, 1, length)) {
+ throw new SecurityException("Invalid signature");
+ }
+ return originalData;
+ }
+
+ private void initializeKeys() throws StorageException, GeneralSecurityException {
+ KeystoreModel model = storage.getObject(KeystoreModel.class, new Request(new Columns.All()));
+ if (model != null) {
+ publicKey = KeyFactory.getInstance("EC")
+ .generatePublic(new X509EncodedKeySpec(model.getPublicKey()));
+ privateKey = KeyFactory.getInstance("EC")
+ .generatePrivate(new PKCS8EncodedKeySpec(model.getPrivateKey()));
+ } else {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
+ generator.initialize(new ECGenParameterSpec("secp256r1"), new SecureRandom());
+ KeyPair pair = generator.generateKeyPair();
+
+ publicKey = pair.getPublic();
+ privateKey = pair.getPrivate();
+
+ model = new KeystoreModel();
+ model.setPublicKey(publicKey.getEncoded());
+ model.setPrivateKey(privateKey.getEncoded());
+ storage.addObject(model, new Request(new Columns.Exclude("id")));
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/signature/KeystoreModel.java b/src/main/java/org/traccar/api/signature/KeystoreModel.java
new file mode 100644
index 000000000..7f3140e81
--- /dev/null
+++ b/src/main/java/org/traccar/api/signature/KeystoreModel.java
@@ -0,0 +1,44 @@
+/*
+ * 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.api.signature;
+
+import org.traccar.model.BaseModel;
+import org.traccar.storage.StorageName;
+
+@StorageName("tc_keystore")
+public class KeystoreModel extends BaseModel {
+
+ private byte[] publicKey;
+
+ public byte[] getPublicKey() {
+ return publicKey;
+ }
+
+ public void setPublicKey(byte[] publicKey) {
+ this.publicKey = publicKey;
+ }
+
+ private byte[] privateKey;
+
+ public byte[] getPrivateKey() {
+ return privateKey;
+ }
+
+ public void setPrivateKey(byte[] privateKey) {
+ this.privateKey = privateKey;
+ }
+
+}
diff --git a/src/main/java/org/traccar/api/signature/TokenManager.java b/src/main/java/org/traccar/api/signature/TokenManager.java
new file mode 100644
index 000000000..3019e12b9
--- /dev/null
+++ b/src/main/java/org/traccar/api/signature/TokenManager.java
@@ -0,0 +1,77 @@
+/*
+ * 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.api.signature;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.codec.binary.Base64;
+import org.traccar.storage.StorageException;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+@Singleton
+public class TokenManager {
+
+ private static final int DEFAULT_EXPIRATION_DAYS = 7;
+
+ private final ObjectMapper objectMapper;
+ private final CryptoManager cryptoManager;
+
+ public static class Data {
+ @JsonProperty("u")
+ private long userId;
+ @JsonProperty("e")
+ private Date expiration;
+ }
+
+ @Inject
+ public TokenManager(ObjectMapper objectMapper, CryptoManager cryptoManager) {
+ this.objectMapper = objectMapper;
+ this.cryptoManager = cryptoManager;
+ }
+
+ public String generateToken(long userId) throws IOException, GeneralSecurityException, StorageException {
+ return generateToken(userId, null);
+ }
+
+ public String generateToken(
+ long userId, Date expiration) throws IOException, GeneralSecurityException, StorageException {
+ Data data = new Data();
+ data.userId = userId;
+ if (expiration != null) {
+ data.expiration = expiration;
+ } else {
+ data.expiration = new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(DEFAULT_EXPIRATION_DAYS));
+ }
+ byte[] encoded = objectMapper.writeValueAsBytes(data);
+ return Base64.encodeBase64URLSafeString(cryptoManager.sign(encoded));
+ }
+
+ public long verifyToken(String token) throws IOException, GeneralSecurityException, StorageException {
+ byte[] encoded = cryptoManager.verify(Base64.decodeBase64(token));
+ Data data = objectMapper.readValue(encoded, Data.class);
+ if (data.expiration.before(new Date())) {
+ throw new SecurityException("Token has expired");
+ }
+ return data.userId;
+ }
+
+}
diff --git a/src/main/java/org/traccar/broadcast/BaseBroadcastService.java b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java
new file mode 100644
index 000000000..a95d333f2
--- /dev/null
+++ b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.broadcast;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.traccar.model.BaseModel;
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+import org.traccar.model.Permission;
+import org.traccar.model.Position;
+
+public abstract class BaseBroadcastService implements BroadcastService {
+
+ private final Set<BroadcastInterface> listeners = new HashSet<>();
+
+ @Override
+ public boolean singleInstance() {
+ return true;
+ }
+
+ @Override
+ public void registerListener(BroadcastInterface listener) {
+ listeners.add(listener);
+ }
+
+ @Override
+ public void updateDevice(boolean local, Device device) {
+ BroadcastMessage message = new BroadcastMessage();
+ message.setDevice(device);
+ sendMessage(message);
+ }
+
+ @Override
+ public void updatePosition(boolean local, Position position) {
+ BroadcastMessage message = new BroadcastMessage();
+ message.setPosition(position);
+ sendMessage(message);
+ }
+
+ @Override
+ public void updateEvent(boolean local, long userId, Event event) {
+ BroadcastMessage message = new BroadcastMessage();
+ message.setUserId(userId);
+ message.setEvent(event);
+ sendMessage(message);
+ }
+
+ @Override
+ public void updateCommand(boolean local, long deviceId) {
+ BroadcastMessage message = new BroadcastMessage();
+ message.setCommandDeviceId(deviceId);
+ sendMessage(message);
+ }
+
+ @Override
+ public void invalidateObject(boolean local, Class<? extends BaseModel> clazz, long id) {
+ BroadcastMessage message = new BroadcastMessage();
+ message.setChanges(Map.of(Permission.getKey(clazz), id));
+ sendMessage(message);
+ }
+
+ @Override
+ public void invalidatePermission(
+ boolean local,
+ Class<? extends BaseModel> clazz1, long id1,
+ Class<? extends BaseModel> clazz2, long id2) {
+ BroadcastMessage message = new BroadcastMessage();
+ message.setChanges(Map.of(Permission.getKey(clazz1), id1, Permission.getKey(clazz2), id2));
+ sendMessage(message);
+ }
+
+ protected abstract void sendMessage(BroadcastMessage message);
+
+ protected void handleMessage(BroadcastMessage message) {
+ if (message.getDevice() != null) {
+ listeners.forEach(listener -> listener.updateDevice(false, message.getDevice()));
+ } else if (message.getPosition() != null) {
+ listeners.forEach(listener -> listener.updatePosition(false, message.getPosition()));
+ } else if (message.getUserId() != null && message.getEvent() != null) {
+ listeners.forEach(listener -> listener.updateEvent(false, message.getUserId(), message.getEvent()));
+ } else if (message.getCommandDeviceId() != null) {
+ listeners.forEach(listener -> listener.updateCommand(false, message.getCommandDeviceId()));
+ } else if (message.getChanges() != null) {
+ var iterator = message.getChanges().entrySet().iterator();
+ if (iterator.hasNext()) {
+ var first = iterator.next();
+ if (iterator.hasNext()) {
+ var second = iterator.next();
+ listeners.forEach(listener -> listener.invalidatePermission(
+ false,
+ Permission.getKeyClass(first.getKey()), first.getValue(),
+ Permission.getKeyClass(second.getKey()), second.getValue()));
+ } else {
+ listeners.forEach(listener -> listener.invalidateObject(
+ false,
+ Permission.getKeyClass(first.getKey()), first.getValue()));
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/broadcast/BroadcastInterface.java b/src/main/java/org/traccar/broadcast/BroadcastInterface.java
new file mode 100644
index 000000000..673ebd8b8
--- /dev/null
+++ b/src/main/java/org/traccar/broadcast/BroadcastInterface.java
@@ -0,0 +1,45 @@
+/*
+ * 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.broadcast;
+
+import org.traccar.model.BaseModel;
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+public interface BroadcastInterface {
+
+ default void updateDevice(boolean local, Device device) {
+ }
+
+ default void updatePosition(boolean local, Position position) {
+ }
+
+ default void updateEvent(boolean local, long userId, Event event) {
+ }
+
+ default void updateCommand(boolean local, long deviceId) {
+ }
+
+ default void invalidateObject(boolean local, Class<? extends BaseModel> clazz, long id) {
+ }
+
+ default void invalidatePermission(
+ boolean local,
+ Class<? extends BaseModel> clazz1, long id1,
+ Class<? extends BaseModel> clazz2, long id2) {
+ }
+}
diff --git a/src/main/java/org/traccar/broadcast/BroadcastMessage.java b/src/main/java/org/traccar/broadcast/BroadcastMessage.java
new file mode 100644
index 000000000..985848d04
--- /dev/null
+++ b/src/main/java/org/traccar/broadcast/BroadcastMessage.java
@@ -0,0 +1,85 @@
+/*
+ * 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.broadcast;
+
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+import java.util.Map;
+
+public class BroadcastMessage {
+
+ private Device device;
+
+ public Device getDevice() {
+ return device;
+ }
+
+ public void setDevice(Device device) {
+ this.device = device;
+ }
+
+ private Position position;
+
+ public Position getPosition() {
+ return position;
+ }
+
+ public void setPosition(Position position) {
+ this.position = position;
+ }
+
+ private Long userId;
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+
+ private Event event;
+
+ public Event getEvent() {
+ return event;
+ }
+
+ public void setEvent(Event event) {
+ this.event = event;
+ }
+
+ private Long commandDeviceId;
+
+ public Long getCommandDeviceId() {
+ return commandDeviceId;
+ }
+
+ public void setCommandDeviceId(Long commandDeviceId) {
+ this.commandDeviceId = commandDeviceId;
+ }
+
+ private Map<String, Long> changes;
+
+ public Map<String, Long> getChanges() {
+ return changes;
+ }
+
+ public void setChanges(Map<String, Long> changes) {
+ this.changes = changes;
+ }
+}
diff --git a/src/main/java/org/traccar/broadcast/BroadcastService.java b/src/main/java/org/traccar/broadcast/BroadcastService.java
new file mode 100644
index 000000000..a86c43b5b
--- /dev/null
+++ b/src/main/java/org/traccar/broadcast/BroadcastService.java
@@ -0,0 +1,23 @@
+/*
+ * 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.broadcast;
+
+import org.traccar.LifecycleObject;
+
+public interface BroadcastService extends LifecycleObject, BroadcastInterface {
+ boolean singleInstance();
+ void registerListener(BroadcastInterface listener);
+}
diff --git a/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java b/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java
new file mode 100644
index 000000000..1c02b319b
--- /dev/null
+++ b/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java
@@ -0,0 +1,112 @@
+/*
+ * 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.broadcast;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.MulticastSocket;
+import java.net.NetworkInterface;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class MulticastBroadcastService extends BaseBroadcastService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(MulticastBroadcastService.class);
+
+ private final ObjectMapper objectMapper;
+
+ private final NetworkInterface networkInterface;
+ private final int port;
+ private final InetSocketAddress group;
+
+ private DatagramSocket publisherSocket;
+
+ private final ExecutorService service = Executors.newSingleThreadExecutor();
+ private final byte[] receiverBuffer = new byte[4096];
+
+ public MulticastBroadcastService(Config config, ObjectMapper objectMapper) throws IOException {
+ this.objectMapper = objectMapper;
+ port = config.getInteger(Keys.BROADCAST_PORT);
+ String interfaceName = config.getString(Keys.BROADCAST_INTERFACE);
+ if (interfaceName.indexOf('.') >= 0 || interfaceName.indexOf(':') >= 0) {
+ networkInterface = NetworkInterface.getByInetAddress(InetAddress.getByName(interfaceName));
+ } else {
+ networkInterface = NetworkInterface.getByName(interfaceName);
+ }
+ InetAddress address = InetAddress.getByName(config.getString(Keys.BROADCAST_ADDRESS));
+ group = new InetSocketAddress(address, port);
+ }
+
+ @Override
+ public boolean singleInstance() {
+ return false;
+ }
+
+ @Override
+ protected void sendMessage(BroadcastMessage message) {
+ try {
+ byte[] buffer = objectMapper.writeValueAsString(message).getBytes(StandardCharsets.UTF_8);
+ DatagramPacket packet = new DatagramPacket(buffer, buffer.length, group);
+ publisherSocket.send(packet);
+ } catch (IOException e) {
+ LOGGER.warn("Broadcast failed", e);
+ }
+ }
+
+ @Override
+ public void start() throws IOException {
+ service.submit(receiver);
+ }
+
+ @Override
+ public void stop() {
+ service.shutdown();
+ }
+
+ private final Runnable receiver = new Runnable() {
+ @Override
+ public void run() {
+ try (MulticastSocket socket = new MulticastSocket(port)) {
+ socket.setNetworkInterface(networkInterface);
+ socket.joinGroup(group, networkInterface);
+ publisherSocket = socket;
+ while (!service.isShutdown()) {
+ DatagramPacket packet = new DatagramPacket(receiverBuffer, receiverBuffer.length);
+ socket.receive(packet);
+ if (networkInterface.inetAddresses().noneMatch(a -> a.equals(packet.getAddress()))) {
+ String data = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8);
+ handleMessage(objectMapper.readValue(data, BroadcastMessage.class));
+ }
+ }
+ publisherSocket = null;
+ socket.leaveGroup(group, networkInterface);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+
+}
diff --git a/src/main/java/org/traccar/api/ObjectMapperProvider.java b/src/main/java/org/traccar/broadcast/NullBroadcastService.java
index f81b20917..f95037990 100644
--- a/src/main/java/org/traccar/api/ObjectMapperProvider.java
+++ b/src/main/java/org/traccar/broadcast/NullBroadcastService.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org)
+ * 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.
@@ -13,20 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.api;
+package org.traccar.broadcast;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.traccar.Context;
+public class NullBroadcastService implements BroadcastService {
-import javax.ws.rs.ext.ContextResolver;
-import javax.ws.rs.ext.Provider;
+ @Override
+ public boolean singleInstance() {
+ return true;
+ }
-@Provider
-public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
+ @Override
+ public void registerListener(BroadcastInterface listener) {
+ }
@Override
- public ObjectMapper getContext(Class<?> type) {
- return Context.getObjectMapper();
+ public void start() throws Exception {
}
+ @Override
+ public void stop() throws Exception {
+ }
}
diff --git a/src/main/java/org/traccar/broadcast/RedisBroadcastService.java b/src/main/java/org/traccar/broadcast/RedisBroadcastService.java
new file mode 100644
index 000000000..e87ad5e61
--- /dev/null
+++ b/src/main/java/org/traccar/broadcast/RedisBroadcastService.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.broadcast;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import java.io.IOException;
+import java.util.UUID;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPubSub;
+import redis.clients.jedis.exceptions.JedisConnectionException;
+import redis.clients.jedis.exceptions.JedisException;
+
+public class RedisBroadcastService extends BaseBroadcastService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(RedisBroadcastService.class);
+
+ private final ObjectMapper objectMapper;
+
+ private final ExecutorService service = Executors.newSingleThreadExecutor();
+
+ private final String url;
+ private final String channel = "traccar";
+
+ private Jedis subscriber;
+ private Jedis publisher;
+
+ private final String id = UUID.randomUUID().toString();
+
+ public RedisBroadcastService(Config config, ObjectMapper objectMapper) throws IOException {
+ this.objectMapper = objectMapper;
+ url = config.getString(Keys.BROADCAST_ADDRESS);
+
+ try {
+ subscriber = new Jedis(url);
+ publisher = new Jedis(url);
+ subscriber.connect();
+ } catch (JedisConnectionException e) {
+ throw new IOException(e);
+ }
+ }
+
+ @Override
+ public boolean singleInstance() {
+ return false;
+ }
+
+ @Override
+ protected void sendMessage(BroadcastMessage message) {
+ try {
+ String payload = id + ":" + objectMapper.writeValueAsString(message);
+ publisher.publish(channel, payload);
+ } catch (IOException e) {
+ LOGGER.warn("Broadcast failed", e);
+ } catch (JedisConnectionException e) {
+ LOGGER.warn("Broadcast failed", e);
+ }
+ }
+
+ @Override
+ public void start() throws IOException {
+ service.submit(receiver);
+ }
+
+ @Override
+ public void stop() {
+ try {
+ if (subscriber != null) {
+ subscriber.close();
+ subscriber = null;
+ }
+ } catch (JedisException e) {
+ LOGGER.warn("Subscriber close failed", e);
+ }
+ try {
+ if (publisher != null) {
+ publisher.close();
+ publisher = null;
+ }
+ } catch (JedisException e) {
+ LOGGER.warn("Publisher close failed", e);
+ }
+ service.shutdown();
+ }
+
+ private final Runnable receiver = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ subscriber.subscribe(new JedisPubSub() {
+ @Override
+ public void onMessage(String messageChannel, String message) {
+ try {
+ String[] parts = message.split(":", 2);
+ if (messageChannel.equals(channel) && parts.length == 2 && !id.equals(parts[0])) {
+ handleMessage(objectMapper.readValue(parts[1], BroadcastMessage.class));
+ }
+ } catch (IOException e) {
+ LOGGER.warn("Broadcast handleMessage failed", e);
+ }
+ }
+ }, channel);
+ } catch (JedisConnectionException e) {
+ throw new RuntimeException(e);
+ } catch (JedisException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+
+}
diff --git a/src/main/java/org/traccar/config/Config.java b/src/main/java/org/traccar/config/Config.java
index 815a6e86a..47e1f0707 100644
--- a/src/main/java/org/traccar/config/Config.java
+++ b/src/main/java/org/traccar/config/Config.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -16,13 +16,19 @@
package org.traccar.config;
import com.google.common.annotations.VisibleForTesting;
+import com.google.inject.name.Named;
+import org.traccar.helper.Log;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.InvalidPropertiesFormatException;
+import java.util.Objects;
import java.util.Properties;
+@Singleton
public class Config {
private final Properties properties = new Properties();
@@ -32,7 +38,8 @@ public class Config {
public Config() {
}
- public Config(String file) throws IOException {
+ @Inject
+ public Config(@Named("configFile") String file) throws IOException {
try {
Properties mainProperties = new Properties();
try (InputStream inputStream = new FileInputStream(file)) {
@@ -50,8 +57,14 @@ public class Config {
useEnvironmentVariables = Boolean.parseBoolean(System.getenv("CONFIG_USE_ENVIRONMENT_VARIABLES"))
|| Boolean.parseBoolean(properties.getProperty("config.useEnvironmentVariables"));
+
+ Log.setupLogger(this);
} catch (InvalidPropertiesFormatException e) {
+ Log.setupDefaultLogger();
throw new RuntimeException("Configuration file is not a valid XML document", e);
+ } catch (Exception e) {
+ Log.setupDefaultLogger();
+ throw e;
}
}
@@ -59,8 +72,7 @@ public class Config {
return hasKey(key.getKey());
}
- @Deprecated
- public boolean hasKey(String key) {
+ private boolean hasKey(String key) {
return useEnvironmentVariables && System.getenv().containsKey(getEnvironmentVariableName(key))
|| properties.containsKey(key);
}
@@ -90,12 +102,7 @@ public class Config {
}
public boolean getBoolean(ConfigKey<Boolean> key) {
- return getBoolean(key.getKey());
- }
-
- @Deprecated
- public boolean getBoolean(String key) {
- return Boolean.parseBoolean(getString(key));
+ return Boolean.parseBoolean(getString(key.getKey()));
}
public int getInteger(ConfigKey<Integer> key) {
@@ -104,11 +111,7 @@ public class Config {
return Integer.parseInt(value);
} else {
Integer defaultValue = key.getDefaultValue();
- if (defaultValue != null) {
- return defaultValue;
- } else {
- return 0;
- }
+ return Objects.requireNonNullElse(defaultValue, 0);
}
}
@@ -127,11 +130,7 @@ public class Config {
return Long.parseLong(value);
} else {
Long defaultValue = key.getDefaultValue();
- if (defaultValue != null) {
- return defaultValue;
- } else {
- return 0;
- }
+ return Objects.requireNonNullElse(defaultValue, 0L);
}
}
@@ -141,11 +140,7 @@ public class Config {
return Double.parseDouble(value);
} else {
Double defaultValue = key.getDefaultValue();
- if (defaultValue != null) {
- return defaultValue;
- } else {
- return 0;
- }
+ return Objects.requireNonNullElse(defaultValue, 0.0);
}
}
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/KeyType.java b/src/main/java/org/traccar/config/KeyType.java
index 57a95c9ec..46628f9fc 100644
--- a/src/main/java/org/traccar/config/KeyType.java
+++ b/src/main/java/org/traccar/config/KeyType.java
@@ -16,7 +16,7 @@
package org.traccar.config;
public enum KeyType {
- GLOBAL,
+ CONFIG,
SERVER,
USER,
DEVICE,
diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java
index ccfe4bee7..27f5f0921 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
/**
* Connection timeout value in seconds. Because sometimes there is no way to detect lost TCP connection old
@@ -65,574 +65,823 @@ 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.GLOBAL));
+ 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 ConfigKey<String> DEVICE_PASSWORD = new StringConfigKey(
+ "devicePassword",
+ List.of(KeyType.DEVICE));
+
+ /**
+ * Device password. Commonly used in some protocol for sending commands.
+ */
+ public static final ConfigSuffix<String> PROTOCOL_DEVICE_PASSWORD = new StringConfigSuffix(
".devicePassword",
- Collections.singletonList(KeyType.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG, KeyType.DEVICE),
+ false);
/**
* 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
/**
- * Skip device connection session cache. Per protocol configuration.
+ * Protocol type for Suntech.
*/
- public static final ConfigSuffix<Boolean> PROTOCOL_IGNORE_SESSIONS_CACHE = new ConfigSuffix<>(
- ".ignoreSessionCache",
- Collections.singletonList(KeyType.GLOBAL));
+ 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));
+
+ /**
+ * Disable commands for the protocol. Not all protocols support this option.
+ */
+ public static final ConfigSuffix<Boolean> PROTOCOL_DISABLE_COMMANDS = new BooleanConfigSuffix(
+ ".disableCommands",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Protocol format. Used by protocols that have configurable message format.
+ */
+ public static final ConfigSuffix<String> PROTOCOL_FORMAT = new StringConfigSuffix(
+ ".format",
+ List.of(KeyType.CONFIG, 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
/**
- * Skip device connection session cache. Global configuration.
+ * Use alternative format for the protocol of commands.
*/
- public static final ConfigKey<Boolean> DECODER_IGNORE_SESSIONS_CACHE = new ConfigKey<>(
- "decoder.ignoreSessionCache",
- Collections.singletonList(KeyType.GLOBAL));
+ public static final ConfigSuffix<Boolean> PROTOCOL_ALTERNATIVE = new BooleanConfigSuffix(
+ ".alternative",
+ List.of(KeyType.CONFIG, KeyType.DEVICE),
+ false);
+
+ /**
+ * Protocol format includes a language field.
+ */
+ public static final ConfigSuffix<Boolean> PROTOCOL_LANGUAGE = new BooleanConfigSuffix(
+ ".language",
+ List.of(KeyType.CONFIG, KeyType.DEVICE),
+ false);
/**
* 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Send device responses immediately before writing it in the database.
+ */
+ public static final ConfigKey<Boolean> SERVER_INSTANT_ACKNOWLEDGEMENT = new BooleanConfigKey(
+ "server.instantAcknowledgement",
+ 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.GLOBAL));
+ 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),
+ 0.0);
+
+ /**
+ * Fuel increase threshold value. When fuel level increases from one position to another for more the value, an
+ * event is generated.
+ */
+ public static final ConfigKey<Double> EVENT_FUEL_INCREASE_THRESHOLD = new DoubleConfigKey(
+ "fuelIncreaseThreshold",
+ List.of(KeyType.SERVER, KeyType.DEVICE),
+ 0.0);
+
+ /**
+ * Speed limit value in knots.
+ */
+ public static final ConfigKey<Double> EVENT_OVERSPEED_LIMIT = new DoubleConfigKey(
+ "speedLimit",
+ List.of(KeyType.SERVER, KeyType.DEVICE),
+ 0.0);
/**
- * If true, the event is generated once at the beginning of overspeeding period.
+ * Speed limit threshold multiplier. For example, if the speed limit is 100, but we only want to generate an event
+ * if the speed is higher than 105, this parameter can be set to 1.05. Default multiplier is 1.0.
*/
- public static final ConfigKey<Boolean> EVENT_OVERSPEED_NOT_REPEAT = new ConfigKey<>(
- "event.overspeed.notRepeat",
- Collections.singletonList(KeyType.GLOBAL));
+ public static final ConfigKey<Double> EVENT_OVERSPEED_THRESHOLD_MULTIPLIER = new DoubleConfigKey(
+ "event.overspeed.thresholdMultiplier",
+ List.of(KeyType.CONFIG),
+ 1.0);
/**
* 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG, KeyType.DEVICE),
+ false);
/**
* 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.GLOBAL),
+ List.of(KeyType.CONFIG, KeyType.DEVICE),
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.GLOBAL),
+ List.of(KeyType.CONFIG),
25.0);
/**
+ * Enable in-memory database instead of an SQL database.
+ */
+ public static final ConfigKey<Boolean> DATABASE_MEMORY = new BooleanConfigKey(
+ "database.memory",
+ List.of(KeyType.CONFIG));
+
+ /**
* 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL),
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
/**
- * By default server syncs with the database if it encounters and unknown device. This flag allows to disable that
+ * Throttle unknown device database queries when it sends repeated requests.
+ */
+ public static final ConfigKey<Boolean> DATABASE_THROTTLE_UNKNOWN = new BooleanConfigKey(
+ "database.throttleUnknown",
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
/**
- * Minimum device refresh timeout in seconds. Default timeout is 5 minutes.
+ * Automatically register unknown devices with regex filter.
*/
- public static final ConfigKey<Long> DATABASE_REFRESH_DELAY = new ConfigKey<>(
- "database.refreshDelay",
- Collections.singletonList(KeyType.GLOBAL),
- 300L);
+ public static final ConfigKey<String> DATABASE_REGISTER_UNKNOWN_REGEX = new StringConfigKey(
+ "database.registerUnknown.regex",
+ List.of(KeyType.CONFIG), "\\w{3,15}");
/**
* 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.GLOBAL));
+ 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.GLOBAL),
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
/**
- * LDAP server URL.
+ * LDAP server URL. For more info check <a href="https://www.traccar.org/ldap/">LDAP config</a>.
*/
- public static final ConfigKey<String> LDAP_URL = new ConfigKey<>(
+ public static final ConfigKey<String> LDAP_URL = new StringConfigKey(
"ldap.url",
- Collections.singletonList(KeyType.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL),
+ 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.GLOBAL),
+ 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.GLOBAL),
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Force OpenID Connect authentication. When enabled, the Traccar login page will be skipped
+ * and users are redirected to the OpenID Connect provider.
+ */
+ public static final ConfigKey<Boolean> OPENID_FORCE = new BooleanConfigKey(
+ "openid.force",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * OpenID Connect Client ID.
+ * This is a unique ID assigned to each application you register with your identity provider.
+ * Required to enable SSO.
+ */
+ public static final ConfigKey<String> OPENID_CLIENT_ID = new StringConfigKey(
+ "openid.clientId",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * OpenID Connect Client Secret.
+ * This is a secret assigned to each application you register with your identity provider.
+ * Required to enable SSO.
+ */
+ public static final ConfigKey<String> OPENID_CLIENT_SECRET = new StringConfigKey(
+ "openid.clientSecret",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * OpenID Connect Issuer (Base) URL.
+ * This is used to automatically configure the authorization, token and user info URLs if provided.
+ */
+ public static final ConfigKey<String> OPENID_ISSUER_URL = new StringConfigKey(
+ "openid.issuerUrl",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * OpenID Connect Authorization URL.
+ * This can usually be found in the documentation of your identity provider or by using the well-known
+ * configuration endpoint, eg. https://auth.example.com//.well-known/openid-configuration
+ * Required to enable SSO if openid.issuerUrl is not set.
+ */
+ public static final ConfigKey<String> OPENID_AUTH_URL = new StringConfigKey(
+ "openid.authUrl",
+ List.of(KeyType.CONFIG));
+ /**
+ * OpenID Connect Token URL.
+ * This can be found in the same ways at openid.authUrl.
+ * Required to enable SSO if openid.issuerUrl is not set.
+ */
+ public static final ConfigKey<String> OPENID_TOKEN_URL = new StringConfigKey(
+ "openid.tokenUrl",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * OpenID Connect User Info URL.
+ * This can be found in the same ways at openid.authUrl.
+ * Required to enable SSO if openid.issuerUrl is not set.
+ */
+ public static final ConfigKey<String> OPENID_USERINFO_URL = new StringConfigKey(
+ "openid.userInfoUrl",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * OpenID Connect group to restrict access to.
+ * If this is not provided, all OpenID users will have access to Traccar.
+ * This option will only work if your OpenID provider supports the groups scope.
+ */
+ public static final ConfigKey<String> OPENID_ALLOW_GROUP = new StringConfigKey(
+ "openid.allowGroup",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * OpenID Connect group to grant admin access.
+ * If this is not provided, no groups will be granted admin access.
+ * This option will only work if your OpenID provider supports the groups scope.
+ */
+ public static final ConfigKey<String> OPENID_ADMIN_GROUP = new StringConfigKey(
+ "openid.adminGroup",
+ 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.GLOBAL),
+ 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<>(
- "status.updateDeviceState",
- Collections.singletonList(KeyType.GLOBAL));
-
- /**
* 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Maximum API requests per second. Above this limit requests and delayed and throttled.
+ */
+ public static final ConfigKey<Integer> WEB_MAX_REQUESTS_PER_SECOND = new IntegerConfigKey(
+ "web.maxRequestsPerSec",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Maximum API request duration in seconds.
+ */
+ public static final ConfigKey<Integer> WEB_MAX_REQUEST_SECONDS = new IntegerConfigKey(
+ "web.maxRequestSec",
+ List.of(KeyType.CONFIG),
+ 600);
+
+ /**
+ * 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 BooleanConfigKey(
+ "web.sanitize",
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
/**
- * WebSocket connection timeout in milliseconds. Default timeout is 10 minutes.
+ * Path to a folder with overrides. It can be used for branding to keep custom logos in a separate place.
*/
- public static final ConfigKey<Long> WEB_TIMEOUT = new ConfigKey<>(
+ public static final ConfigKey<String> WEB_OVERRIDE = new StringConfigKey(
+ "web.override",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * WebSocket connection timeout in milliseconds. Default timeout is 5 minutes.
+ */
+ public static final ConfigKey<Long> WEB_TIMEOUT = new LongConfigKey(
"web.timeout",
- Collections.singletonList(KeyType.GLOBAL),
- 60000L);
+ List.of(KeyType.CONFIG),
+ 300000L);
/**
* 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * A token to login as a virtual admin account. Can be used to restore access in case of issues with regular admin
+ * login. For example, if password is lost and can't be restored.
+ */
+ public static final ConfigKey<String> WEB_SERVICE_ACCOUNT_TOKEN = new StringConfigKey(
+ "web.serviceAccountToken",
+ 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.GLOBAL));
+ 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.GLOBAL),
+ 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.
+ * Host for raw data forwarding.
*/
- public static final ConfigKey<String> FORWARD_URL = new ConfigKey<>(
- "forward.url",
- Collections.singletonList(KeyType.GLOBAL));
+ public static final ConfigKey<String> SERVER_FORWARD = new StringConfigKey(
+ "server.forward",
+ List.of(KeyType.CONFIG));
/**
- * Additional HTTP header, can be used for authorization.
+ * Position forwarding format. Available options are "url", "json" and "kafka". Default is "url".
*/
- public static final ConfigKey<String> FORWARD_HEADER = new ConfigKey<>(
- "forward.header",
- Collections.singletonList(KeyType.GLOBAL));
+ public static final ConfigKey<String> FORWARD_TYPE = new StringConfigKey(
+ "forward.type",
+ List.of(KeyType.CONFIG),
+ "url");
+
+ /**
+ * Position forwarding AMQP exchange.
+ */
+ public static final ConfigKey<String> FORWARD_EXCHANGE = new StringConfigKey(
+ "forward.exchange",
+ List.of(KeyType.CONFIG),
+ "traccar");
/**
- * Boolean value to enable forwarding in JSON format.
+ * Position forwarding Kafka topic or AQMP Routing Key.
*/
- public static final ConfigKey<Boolean> FORWARD_JSON = new ConfigKey<>(
- "forward.json",
- Collections.singletonList(KeyType.GLOBAL));
+ public static final ConfigKey<String> FORWARD_TOPIC = new StringConfigKey(
+ "forward.topic",
+ List.of(KeyType.CONFIG),
+ "positions");
/**
- * Boolean value to enable URL parameters in json mode. For example, {uniqueId} for device identifier,
+ * 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<Boolean> FORWARD_URL_VARIABLES = new ConfigKey<>(
- "forward.urlVariables",
- Collections.singletonList(KeyType.GLOBAL));
+ public static final ConfigKey<String> FORWARD_URL = new StringConfigKey(
+ "forward.url",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Additional HTTP header, can be used for authorization.
+ */
+ public static final ConfigKey<String> FORWARD_HEADER = new StringConfigKey(
+ "forward.header",
+ List.of(KeyType.CONFIG));
/**
* Position forwarding retrying enable. When enabled, additional attempts are made to deliver positions. If initial
@@ -641,589 +890,808 @@ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG),
+ 100);
/**
* 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.GLOBAL));
+ List.of(KeyType.CONFIG),
+ 10);
/**
* 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.GLOBAL));
+ List.of(KeyType.CONFIG),
+ 100);
+
+ /**
+ * Events forwarding format. Available options are "json" and "kafka". Default is "json".
+ */
+ public static final ConfigKey<String> EVENT_FORWARD_TYPE = new StringConfigKey(
+ "event.forward.type",
+ List.of(KeyType.CONFIG),
+ "json");
+
+ /**
+ * Events forwarding AMQP exchange.
+ */
+ public static final ConfigKey<String> EVENT_FORWARD_EXCHANGE = new StringConfigKey(
+ "event.forward.exchange",
+ List.of(KeyType.CONFIG),
+ "traccar");
+
+ /**
+ * Events forwarding Kafka topic or AQMP Routing Key.
+ */
+ public static final ConfigKey<String> EVENT_FORWARD_TOPIC = new StringConfigKey(
+ "event.forward.topic",
+ List.of(KeyType.CONFIG),
+ "events");
/**
* 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
/**
- * Enable commands queuing when devices are offline. Commands are buffered in memory only, so restarting service
- * will clear the buffer.
+ * Root folder for all template files.
*/
- public static final ConfigKey<Boolean> COMMANDS_QUEUEING = new ConfigKey<>(
- "commands.queueing",
- Collections.singletonList(KeyType.GLOBAL));
+ public static final ConfigKey<String> TEMPLATES_ROOT = new StringConfigKey(
+ "templates.root",
+ List.of(KeyType.CONFIG),
+ "templates");
+
+ /**
+ * Log emails instead of sending them via SMTP. Intended for testing purposes only.
+ */
+ public static final ConfigKey<Boolean> MAIL_DEBUG = new BooleanConfigKey(
+ "mail.debug",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Restrict global SMTP configuration to system messages only (e.g. password reset).
+ */
+ public static final ConfigKey<Boolean> MAIL_SMTP_SYSTEM_ONLY = new BooleanConfigKey(
+ "mail.smtp.systemOnly",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Force SMTP settings from the config file and ignore user attributes.
+ */
+ public static final ConfigKey<Boolean> MAIL_SMTP_IGNORE_USER_CONFIG = new BooleanConfigKey(
+ "mail.smtp.ignoreUserConfig",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * The SMTP server to connect to.
+ */
+ public static final ConfigKey<String> MAIL_SMTP_HOST = new StringConfigKey(
+ "mail.smtp.host",
+ List.of(KeyType.CONFIG, KeyType.USER));
+
+ /**
+ * The SMTP server port to connect. Defaults to 25.
+ */
+ public static final ConfigKey<Integer> MAIL_SMTP_PORT = new IntegerConfigKey(
+ "mail.smtp.port",
+ List.of(KeyType.CONFIG, KeyType.USER),
+ 25);
+
+ /**
+ * Email transport protocol. Default value is "smtp".
+ */
+ public static final ConfigKey<String> MAIL_TRANSPORT_PROTOCOL = new StringConfigKey(
+ "mail.transport.protocol",
+ List.of(KeyType.CONFIG, KeyType.USER),
+ "smtp");
+
+ /**
+ * If true, enables the use of the STARTTLS command (if supported by the server) to switch the connection to a
+ * TLS-protected connection before issuing any login commands.
+ */
+ public static final ConfigKey<Boolean> MAIL_SMTP_STARTTLS_ENABLE = new BooleanConfigKey(
+ "mail.smtp.starttls.enable",
+ List.of(KeyType.CONFIG, KeyType.USER));
+
+ /**
+ * If true, requires the use of the STARTTLS command. If the server doesn't support the STARTTLS command, or the
+ * command fails, the connect method will fail.
+ */
+ public static final ConfigKey<Boolean> MAIL_SMTP_STARTTLS_REQUIRED = new BooleanConfigKey(
+ "mail.smtp.starttls.required",
+ List.of(KeyType.CONFIG, KeyType.USER));
+
+ /**
+ * If set to true, use SSL to connect and use the SSL port by default.
+ */
+ public static final ConfigKey<Boolean> MAIL_SMTP_SSL_ENABLE = new BooleanConfigKey(
+ "mail.smtp.ssl.enable",
+ List.of(KeyType.CONFIG, KeyType.USER));
+
+ /**
+ * If set to "*", all hosts are trusted. If set to a whitespace separated list of hosts, those hosts are trusted.
+ * Otherwise, trust depends on the certificate the server presents.
+ */
+ public static final ConfigKey<String> MAIL_SMTP_SSL_TRUST = new StringConfigKey(
+ "mail.smtp.ssl.trust",
+ List.of(KeyType.CONFIG, KeyType.USER));
+
+ /**
+ * Specifies the SSL protocols that will be enabled for SSL connections.
+ */
+ public static final ConfigKey<String> MAIL_SMTP_SSL_PROTOCOLS = new StringConfigKey(
+ "mail.smtp.ssl.protocols",
+ List.of(KeyType.CONFIG, KeyType.USER));
+
+ /**
+ * SMTP connection username.
+ */
+ public static final ConfigKey<String> MAIL_SMTP_USERNAME = new StringConfigKey(
+ "mail.smtp.username",
+ List.of(KeyType.CONFIG, KeyType.USER));
+
+ /**
+ * SMTP connection password.
+ */
+ public static final ConfigKey<String> MAIL_SMTP_PASSWORD = new StringConfigKey(
+ "mail.smtp.password",
+ List.of(KeyType.CONFIG, KeyType.USER));
+
+ /**
+ * Email address to use for SMTP MAIL command.
+ */
+ public static final ConfigKey<String> MAIL_SMTP_FROM = new StringConfigKey(
+ "mail.smtp.from",
+ List.of(KeyType.CONFIG, KeyType.USER));
+
+ /**
+ * The personal name for the email from address.
+ */
+ public static final ConfigKey<String> MAIL_SMTP_FROM_NAME = new StringConfigKey(
+ "mail.smtp.fromName",
+ List.of(KeyType.CONFIG, KeyType.USER));
/**
* 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.GLOBAL));
+ 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.GLOBAL),
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Enabled notification options. Comma-separated string is expected.
+ * Example: web,mail,sms
+ */
+ public static final ConfigKey<String> NOTIFICATOR_TYPES = new StringConfigKey(
+ "notificator.types",
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
/**
- * Firebase server API key for push notifications.
+ * Firebase service account JSON.
*/
- public static final ConfigKey<String> NOTIFICATOR_FIREBASE_KEY = new ConfigKey<>(
- "notificator.firebase.key",
- Collections.singletonList(KeyType.GLOBAL));
+ public static final ConfigKey<String> NOTIFICATOR_FIREBASE_SERVICE_ACCOUNT = new StringConfigKey(
+ "notificator.firebase.serviceAccount",
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Time threshold for fast reports. Fast reports are more efficient, but less accurate and missing some information.
+ * The value is in seconds. One day by default.
+ */
+ public static final ConfigKey<Long> REPORT_FAST_THRESHOLD = new LongConfigKey(
+ "report.fastThreshold",
+ List.of(KeyType.CONFIG),
+ 86400L);
/**
* 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.GLOBAL),
+ List.of(KeyType.CONFIG, KeyType.DEVICE),
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.GLOBAL),
+ List.of(KeyType.CONFIG, KeyType.DEVICE),
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.GLOBAL),
+ List.of(KeyType.CONFIG, KeyType.DEVICE),
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.GLOBAL),
+ List.of(KeyType.CONFIG, KeyType.DEVICE),
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.GLOBAL));
+ List.of(KeyType.CONFIG, KeyType.DEVICE),
+ false);
+
+ /**
+ * Ignore odometer value reported by the device and use server-calculated total distance instead. This is useful
+ * if device reports invalid or zero odometer values.
+ */
+ public static final ConfigKey<Boolean> REPORT_IGNORE_ODOMETER = new BooleanConfigKey(
+ "report.ignoreOdometer",
+ List.of(KeyType.CONFIG),
+ false);
/**
* 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Filter messages that do not have GPS location. If they are not filtered, they will include the last known
+ * location.
+ */
+ public static final ConfigKey<Boolean> FILTER_OUTDATED = new BooleanConfigKey(
+ "filter.outdated",
+ 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.
+ * Filter records with fix time in the future. The value is specified in seconds. Records that have fix time more
+ * than the 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Filter records with fix time in the past. The value is specified in seconds. Records that have fix time more
+ * than the specified number of seconds before current server time would be filtered out.
+ */
+ public static final ConfigKey<Long> FILTER_PAST = new LongConfigKey(
+ "filter.past",
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
/**
* Filter records by Maximum Speed value in knots. Can be used to filter jumps to far locations even if Position
* appears valid or if Position `speed` field reported by the device is also within limits. Calculates speed from
* the distance to the previous position and the elapsed time.
- *
* 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Filter position if the daily limit is exceeded for the device.
+ */
+ public static final ConfigKey<Integer> FILTER_DAILY_LIMIT = new IntegerConfigKey(
+ "filter.dailyLimit",
+ List.of(KeyType.CONFIG));
/**
* If false, the server expects all locations to come sequentially (for each device). Filter checks for duplicates,
* distance, speed, or time period only against the location that was last received by server.
- *
* If true, the server expects locations to come at random order (since tracking device might go offline).
* 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * List of protocols to enable. If not specified, Traccar enabled all protocols that have port numbers listed.
+ * The value is a comma-separated list of protocol names.
+ * Example value: teltonika,osmand
+ */
+ public static final ConfigKey<String> PROTOCOLS_ENABLE = new StringConfigKey(
+ "protocols.enable",
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
-
- /**
- * Enable engine hours calculation on the server side. It uses ignition value to determine engine state.
- */
- public static final ConfigKey<Boolean> PROCESSING_ENGINE_HOURS_ENABLE = new ConfigKey<>(
- "processing.engineHours.enable",
- Collections.singletonList(KeyType.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
/**
- * Enable computed attributes processing.
+ * List of attributes to copy. Attributes should be separated by a comma without any spacing.
+ * For example: alarm,ignition
*/
- public static final ConfigKey<Boolean> PROCESSING_COMPUTED_ATTRIBUTES_ENABLE = new ConfigKey<>(
- "processing.computedAttributes.enable",
- Collections.singletonList(KeyType.GLOBAL));
+ public static final ConfigKey<String> PROCESSING_COPY_ATTRIBUTES = new StringConfigKey(
+ "processing.copyAttributes",
+ List.of(KeyType.CONFIG, KeyType.DEVICE));
/**
* 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Enable local variables declaration.
+ */
+ public static final ConfigKey<Boolean> PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES = new BooleanConfigKey(
+ "processing.computedAttributes.localVariables",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Enable loops processing.
+ */
+ public static final ConfigKey<Boolean> PROCESSING_COMPUTED_ATTRIBUTES_LOOPS = new BooleanConfigKey(
+ "processing.computedAttributes.loops",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Enable new instances creation.
+ * When disabled, parsing a script/expression using 'new(...)' will throw a parsing exception;
+ */
+ public static final ConfigKey<Boolean> PROCESSING_COMPUTED_ATTRIBUTES_NEW_INSTANCE_CREATION = new BooleanConfigKey(
+ "processing.computedAttributes.newInstanceCreation",
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Reuse last geolocation result if network details have not changed.
+ */
+ public static final ConfigKey<Boolean> GEOLOCATION_REUSE = new BooleanConfigKey(
+ "geolocation.reuse",
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
-
- /**
- * Enable Jetty Request Log.
- */
- public static final ConfigKey<Boolean> WEB_REQUEST_LOG_ENABLE = new ConfigKey<>(
- "web.requestLog.enable",
- Collections.singletonList(KeyType.GLOBAL));
+ List.of(KeyType.CONFIG));
/**
* Jetty Request Log Path.
@@ -1231,82 +1699,136 @@ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Public URL for the web app. Used for notification, report link and OpenID Connect.
+ * 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 StringConfigKey(
+ "web.url",
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Log executed SQL queries.
+ */
+ public static final ConfigKey<Boolean> LOGGER_QUERIES = new BooleanConfigKey(
+ "logger.queries",
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ 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.GLOBAL));
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Log file rotation interval, the default rotation interval is once a day.
+ * This option is ignored if 'logger.rotate' = false
+ * Available options: day, hour
+ */
+ public static final ConfigKey<String> LOGGER_ROTATE_INTERVAL = new StringConfigKey(
+ "logger.rotate.interval",
+ List.of(KeyType.CONFIG),
+ "day");
/**
* 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.GLOBAL),
+ List.of(KeyType.CONFIG),
"time,position,speed,course,accuracy,result");
+ /**
+ * Broadcast method. Available options are "multicast" and "redis". By default (if the value is not
+ * specified or does not matches available options) server disables broadcast.
+ */
+ public static final ConfigKey<String> BROADCAST_TYPE = new StringConfigKey(
+ "broadcast.type",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Multicast interface. It can be either an IP address or an interface name.
+ */
+ public static final ConfigKey<String> BROADCAST_INTERFACE = new StringConfigKey(
+ "broadcast.interface",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Multicast address or Redis URL for broadcasting synchronization events.
+ */
+ public static final ConfigKey<String> BROADCAST_ADDRESS = new StringConfigKey(
+ "broadcast.address",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Multicast port for broadcasting synchronization events.
+ */
+ public static final ConfigKey<Integer> BROADCAST_PORT = new IntegerConfigKey(
+ "broadcast.port",
+ List.of(KeyType.CONFIG));
+
}
diff --git a/src/main/java/org/traccar/database/AttributesManager.java b/src/main/java/org/traccar/database/AttributesManager.java
deleted file mode 100644
index 28816645a..000000000
--- a/src/main/java/org/traccar/database/AttributesManager.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.database;
-
-import org.traccar.model.Attribute;
-
-public class AttributesManager extends ExtendedObjectManager<Attribute> {
-
- public AttributesManager(DataManager dataManager) {
- super(dataManager, Attribute.class);
- }
-
- @Override
- public void updateCachedItem(Attribute attribute) {
- Attribute cachedAttribute = getById(attribute.getId());
- cachedAttribute.setDescription(attribute.getDescription());
- cachedAttribute.setAttribute(attribute.getAttribute());
- cachedAttribute.setExpression(attribute.getExpression());
- cachedAttribute.setType(attribute.getType());
- }
-
-}
diff --git a/src/main/java/org/traccar/database/BaseObjectManager.java b/src/main/java/org/traccar/database/BaseObjectManager.java
deleted file mode 100644
index dd8b3bae4..000000000
--- a/src/main/java/org/traccar/database/BaseObjectManager.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.database;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.model.BaseModel;
-import org.traccar.storage.StorageException;
-
-public class BaseObjectManager<T extends BaseModel> {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(BaseObjectManager.class);
-
- private final ReadWriteLock lock = new ReentrantReadWriteLock();
-
- private final DataManager dataManager;
-
- private final Class<T> baseClass;
- private Map<Long, T> items;
-
- protected BaseObjectManager(DataManager dataManager, Class<T> baseClass) {
- this.dataManager = dataManager;
- this.baseClass = baseClass;
- refreshItems();
- }
-
- protected final void readLock() {
- lock.readLock().lock();
- }
-
- protected final void readUnlock() {
- lock.readLock().unlock();
- }
-
- protected final void writeLock() {
- lock.writeLock().lock();
- }
-
- protected final void writeUnlock() {
- lock.writeLock().unlock();
- }
-
- protected final DataManager getDataManager() {
- return dataManager;
- }
-
- protected final Class<T> getBaseClass() {
- return baseClass;
- }
-
- public T getById(long itemId) {
- try {
- readLock();
- return items.get(itemId);
- } finally {
- readUnlock();
- }
- }
-
- public void refreshItems() {
- if (dataManager != null) {
- try {
- writeLock();
- Collection<T> databaseItems = dataManager.getObjects(baseClass);
- if (items == null) {
- items = new ConcurrentHashMap<>(databaseItems.size());
- }
- Set<Long> databaseItemIds = new HashSet<>();
- for (T item : databaseItems) {
- databaseItemIds.add(item.getId());
- if (items.containsKey(item.getId())) {
- updateCachedItem(item);
- } else {
- addNewItem(item);
- }
- }
- for (Long cachedItemId : items.keySet()) {
- if (!databaseItemIds.contains(cachedItemId)) {
- removeCachedItem(cachedItemId);
- }
- }
- } catch (StorageException error) {
- LOGGER.warn("Error refreshing items", error);
- } finally {
- writeUnlock();
- }
- }
- }
-
- protected void addNewItem(T item) {
- try {
- writeLock();
- items.put(item.getId(), item);
- } finally {
- writeUnlock();
- }
- }
-
- public void addItem(T item) throws StorageException {
- dataManager.addObject(item);
- addNewItem(item);
- }
-
- protected void updateCachedItem(T item) {
- try {
- writeLock();
- items.put(item.getId(), item);
- } finally {
- writeUnlock();
- }
- }
-
- public void updateItem(T item) throws StorageException {
- dataManager.updateObject(item);
- updateCachedItem(item);
- }
-
- protected void removeCachedItem(long itemId) {
- try {
- writeLock();
- items.remove(itemId);
- } finally {
- writeUnlock();
- }
- }
-
- public void removeItem(long itemId) throws StorageException {
- BaseModel item = getById(itemId);
- if (item != null) {
- dataManager.removeObject(baseClass, itemId);
- removeCachedItem(itemId);
- }
- }
-
- public final Collection<T> getItems(Set<Long> itemIds) {
- Collection<T> result = new LinkedList<>();
- for (long itemId : itemIds) {
- T item = getById(itemId);
- if (item != null) {
- result.add(item);
- }
- }
- return result;
- }
-
- public Set<Long> getAllItems() {
- try {
- readLock();
- return items.keySet();
- } finally {
- readUnlock();
- }
- }
-
-}
diff --git a/src/main/java/org/traccar/database/CommandsManager.java b/src/main/java/org/traccar/database/CommandsManager.java
index 843c89e82..fb8f2f9d6 100644
--- a/src/main/java/org/traccar/database/CommandsManager.java
+++ b/src/main/java/org/traccar/database/CommandsManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,177 +16,112 @@
*/
package org.traccar.database;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.traccar.BaseProtocol;
-import org.traccar.Context;
+import org.traccar.ServerManager;
+import org.traccar.broadcast.BroadcastInterface;
+import org.traccar.broadcast.BroadcastService;
import org.traccar.model.Command;
-import org.traccar.model.Typed;
+import org.traccar.model.Device;
import org.traccar.model.Position;
-
-public class CommandsManager extends ExtendedObjectManager<Command> {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(CommandsManager.class);
-
- private final Map<Long, Queue<Command>> deviceQueues = new ConcurrentHashMap<>();
-
- private final boolean queueing;
-
- public CommandsManager(DataManager dataManager, boolean queueing) {
- super(dataManager, Command.class);
- this.queueing = queueing;
- }
-
- public boolean checkDeviceCommand(long deviceId, long commandId) {
- return !getAllDeviceItems(deviceId).contains(commandId);
+import org.traccar.model.QueuedCommand;
+import org.traccar.session.ConnectionManager;
+import org.traccar.session.DeviceSession;
+import org.traccar.sms.SmsManager;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Order;
+import org.traccar.storage.query.Request;
+
+import jakarta.annotation.Nullable;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.Collection;
+import java.util.stream.Collectors;
+
+@Singleton
+public class CommandsManager implements BroadcastInterface {
+
+ private final Storage storage;
+ private final ServerManager serverManager;
+ private final SmsManager smsManager;
+ private final ConnectionManager connectionManager;
+ private final BroadcastService broadcastService;
+
+ @Inject
+ public CommandsManager(
+ Storage storage, ServerManager serverManager, @Nullable SmsManager smsManager,
+ ConnectionManager connectionManager, BroadcastService broadcastService) {
+ this.storage = storage;
+ this.serverManager = serverManager;
+ this.smsManager = smsManager;
+ this.connectionManager = connectionManager;
+ this.broadcastService = broadcastService;
+ broadcastService.registerListener(this);
}
public boolean sendCommand(Command command) throws Exception {
long deviceId = command.getDeviceId();
- if (command.getId() != 0) {
- command = getById(command.getId()).clone();
- command.setDeviceId(deviceId);
- }
if (command.getTextChannel()) {
- Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId);
- String phone = Context.getIdentityManager().getById(deviceId).getPhone();
- if (lastPosition != null) {
- BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol());
- protocol.sendTextCommand(phone, command);
+ if (smsManager == null) {
+ throw new RuntimeException("SMS not configured");
+ }
+ Device device = storage.getObject(Device.class, new Request(
+ new Columns.Include("positionId", "phone"), new Condition.Equals("id", deviceId)));
+ Position position = storage.getObject(Position.class, new Request(
+ new Columns.All(), new Condition.Equals("id", device.getPositionId())));
+ if (position != null) {
+ BaseProtocol protocol = serverManager.getProtocol(position.getProtocol());
+ protocol.sendTextCommand(device.getPhone(), command);
} else if (command.getType().equals(Command.TYPE_CUSTOM)) {
- if (Context.getSmsManager() != null) {
- Context.getSmsManager().sendMessageSync(phone, command.getString(Command.KEY_DATA), true);
- } else {
- throw new RuntimeException("SMS is not enabled");
- }
+ smsManager.sendMessage(device.getPhone(), command.getString(Command.KEY_DATA), true);
} else {
throw new RuntimeException("Command " + command.getType() + " is not supported");
}
} else {
- ActiveDevice activeDevice = Context.getConnectionManager().getActiveDevice(deviceId);
- if (activeDevice != null) {
- if (activeDevice.supportsLiveCommands()) {
- activeDevice.sendCommand(command);
- } else {
- getDeviceQueue(deviceId).add(command);
- return false;
- }
- } else if (!queueing) {
- throw new RuntimeException("Device is not online");
+ DeviceSession deviceSession = connectionManager.getDeviceSession(deviceId);
+ if (deviceSession != null && deviceSession.supportsLiveCommands()) {
+ deviceSession.sendCommand(command);
} else {
- getDeviceQueue(deviceId).add(command);
+ storage.addObject(QueuedCommand.fromCommand(command), new Request(new Columns.Exclude("id")));
+ broadcastService.updateCommand(true, deviceId);
return false;
}
}
return true;
}
- public Collection<Long> getSupportedCommands(long deviceId) {
- List<Long> result = new ArrayList<>();
- Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId);
- for (long commandId : getAllDeviceItems(deviceId)) {
- Command command = getById(commandId);
- if (lastPosition != null) {
- BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol());
- if (command.getTextChannel() && protocol.getSupportedTextCommands().contains(command.getType())
- || !command.getTextChannel()
- && protocol.getSupportedDataCommands().contains(command.getType())) {
- result.add(commandId);
- }
- } else if (command.getType().equals(Command.TYPE_CUSTOM)) {
- result.add(commandId);
- }
- }
- return result;
- }
-
- public Collection<Typed> getCommandTypes(long deviceId, boolean textChannel) {
- Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId);
- if (lastPosition != null) {
- return getCommandTypes(lastPosition.getProtocol(), textChannel);
- } else {
- return Collections.singletonList(new Typed(Command.TYPE_CUSTOM));
- }
- }
-
- public Collection<Typed> getCommandTypes(String protocolName, boolean textChannel) {
- List<Typed> result = new ArrayList<>();
- BaseProtocol protocol = Context.getServerManager().getProtocol(protocolName);
- Collection<String> commands;
- commands = textChannel ? protocol.getSupportedTextCommands() : protocol.getSupportedDataCommands();
- for (String commandKey : commands) {
- result.add(new Typed(commandKey));
- }
- return result;
- }
-
- public Collection<Typed> getAllCommandTypes() {
- List<Typed> result = new ArrayList<>();
- Field[] fields = Command.class.getDeclaredFields();
- for (Field field : fields) {
- if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("TYPE_")) {
- try {
- result.add(new Typed(field.get(null).toString()));
- } catch (IllegalArgumentException | IllegalAccessException error) {
- LOGGER.warn("Get command types error", error);
- }
- }
- }
- return result;
- }
-
- private Queue<Command> getDeviceQueue(long deviceId) {
- Queue<Command> deviceQueue;
- try {
- readLock();
- deviceQueue = deviceQueues.get(deviceId);
- } finally {
- readUnlock();
- }
- if (deviceQueue != null) {
- return deviceQueue;
- } else {
- try {
- writeLock();
- return deviceQueues.computeIfAbsent(deviceId, key -> new ConcurrentLinkedQueue<>());
- } finally {
- writeUnlock();
- }
- }
- }
-
public Collection<Command> readQueuedCommands(long deviceId) {
return readQueuedCommands(deviceId, Integer.MAX_VALUE);
}
public Collection<Command> readQueuedCommands(long deviceId, int count) {
- Queue<Command> deviceQueue;
try {
- readLock();
- deviceQueue = deviceQueues.get(deviceId);
- } finally {
- readUnlock();
+ var commands = storage.getObjects(QueuedCommand.class, new Request(
+ new Columns.All(),
+ new Condition.Equals("deviceId", deviceId),
+ new Order("id", false, count)));
+ for (var command : commands) {
+ storage.removeObject(QueuedCommand.class, new Request(
+ new Condition.Equals("id", command.getId())));
+ }
+ return commands.stream().map(QueuedCommand::toCommand).collect(Collectors.toList());
+ } catch (StorageException e) {
+ throw new RuntimeException(e);
}
- Collection<Command> result = new ArrayList<>();
- if (deviceQueue != null) {
- Command command = deviceQueue.poll();
- while (command != null && result.size() < count) {
- result.add(command);
- command = deviceQueue.poll();
+ }
+
+ @Override
+ public void updateCommand(boolean local, long deviceId) {
+ if (!local) {
+ DeviceSession deviceSession = connectionManager.getDeviceSession(deviceId);
+ if (deviceSession != null && deviceSession.supportsLiveCommands()) {
+ for (Command command : readQueuedCommands(deviceId)) {
+ deviceSession.sendCommand(command);
+ }
}
}
- return result;
}
}
diff --git a/src/main/java/org/traccar/database/ConnectionManager.java b/src/main/java/org/traccar/database/ConnectionManager.java
deleted file mode 100644
index 359061f00..000000000
--- a/src/main/java/org/traccar/database/ConnectionManager.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright 2015 - 2020 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.database;
-
-import io.netty.channel.Channel;
-import io.netty.util.Timeout;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.GlobalTimer;
-import org.traccar.Main;
-import org.traccar.Protocol;
-import org.traccar.config.Keys;
-import org.traccar.handler.events.MotionEventHandler;
-import org.traccar.handler.events.OverspeedEventHandler;
-import org.traccar.model.Device;
-import org.traccar.model.DeviceState;
-import org.traccar.model.Event;
-import org.traccar.model.Position;
-import org.traccar.storage.StorageException;
-
-import java.net.SocketAddress;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-
-public class ConnectionManager {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionManager.class);
-
- private final long deviceTimeout;
- private final boolean updateDeviceState;
-
- private final Map<Long, ActiveDevice> activeDevices = new ConcurrentHashMap<>();
- private final Map<Long, Set<UpdateListener>> listeners = new ConcurrentHashMap<>();
- private final Map<Long, Timeout> timeouts = new ConcurrentHashMap<>();
-
- public ConnectionManager() {
- deviceTimeout = Context.getConfig().getLong(Keys.STATUS_TIMEOUT) * 1000;
- updateDeviceState = Context.getConfig().getBoolean(Keys.STATUS_UPDATE_DEVICE_STATE);
- }
-
- public void addActiveDevice(long deviceId, Protocol protocol, Channel channel, SocketAddress remoteAddress) {
- activeDevices.put(deviceId, new ActiveDevice(deviceId, protocol, channel, remoteAddress));
- }
-
- public void removeActiveDevice(Channel channel) {
- for (ActiveDevice activeDevice : activeDevices.values()) {
- if (activeDevice.getChannel() == channel) {
- updateDevice(activeDevice.getDeviceId(), Device.STATUS_OFFLINE, null);
- activeDevices.remove(activeDevice.getDeviceId());
- break;
- }
- }
- }
-
- public ActiveDevice getActiveDevice(long deviceId) {
- return activeDevices.get(deviceId);
- }
-
- public void updateDevice(final long deviceId, String status, Date time) {
- Device device = Context.getIdentityManager().getById(deviceId);
- if (device == null) {
- return;
- }
-
- String oldStatus = device.getStatus();
- device.setStatus(status);
-
- if (!status.equals(oldStatus)) {
- String eventType;
- Map<Event, Position> events = new HashMap<>();
- switch (status) {
- case Device.STATUS_ONLINE:
- eventType = Event.TYPE_DEVICE_ONLINE;
- break;
- case Device.STATUS_UNKNOWN:
- eventType = Event.TYPE_DEVICE_UNKNOWN;
- if (updateDeviceState) {
- events.putAll(updateDeviceState(deviceId));
- }
- break;
- default:
- eventType = Event.TYPE_DEVICE_OFFLINE;
- if (updateDeviceState) {
- events.putAll(updateDeviceState(deviceId));
- }
- break;
- }
- events.put(new Event(eventType, deviceId), null);
- Context.getNotificationManager().updateEvents(events);
- }
-
- Timeout timeout = timeouts.remove(deviceId);
- if (timeout != null) {
- timeout.cancel();
- }
-
- if (time != null) {
- device.setLastUpdate(time);
- }
-
- if (status.equals(Device.STATUS_ONLINE)) {
- timeouts.put(deviceId, GlobalTimer.getTimer().newTimeout(timeout1 -> {
- if (!timeout1.isCancelled()) {
- updateDevice(deviceId, Device.STATUS_UNKNOWN, null);
- }
- }, deviceTimeout, TimeUnit.MILLISECONDS));
- }
-
- try {
- Context.getDeviceManager().updateDeviceStatus(device);
- } catch (StorageException e) {
- LOGGER.warn("Update device status error", e);
- }
-
- updateDevice(device);
- }
-
- public Map<Event, Position> updateDeviceState(long deviceId) {
- DeviceState deviceState = Context.getDeviceManager().getDeviceState(deviceId);
- Map<Event, Position> result = new HashMap<>();
-
- Map<Event, Position> event = Main.getInjector()
- .getInstance(MotionEventHandler.class).updateMotionState(deviceState);
- if (event != null) {
- result.putAll(event);
- }
-
- event = Main.getInjector().getInstance(OverspeedEventHandler.class)
- .updateOverspeedState(deviceState, Context.getDeviceManager().
- lookupAttributeDouble(deviceId, OverspeedEventHandler.ATTRIBUTE_SPEED_LIMIT, 0, true, false));
- if (event != null) {
- result.putAll(event);
- }
-
- return result;
- }
-
- public synchronized void sendKeepalive() {
- for (Set<UpdateListener> userListeners : listeners.values()) {
- for (UpdateListener listener : userListeners) {
- listener.onKeepalive();
- }
- }
- }
-
- public synchronized void updateDevice(Device device) {
- for (long userId : Context.getPermissionsManager().getDeviceUsers(device.getId())) {
- if (listeners.containsKey(userId)) {
- for (UpdateListener listener : listeners.get(userId)) {
- listener.onUpdateDevice(device);
- }
- }
- }
- }
-
- public synchronized void updatePosition(Position position) {
- long deviceId = position.getDeviceId();
-
- for (long userId : Context.getPermissionsManager().getDeviceUsers(deviceId)) {
- if (listeners.containsKey(userId)) {
- for (UpdateListener listener : listeners.get(userId)) {
- listener.onUpdatePosition(position);
- }
- }
- }
- }
-
- public synchronized void updateEvent(long userId, Event event) {
- if (listeners.containsKey(userId)) {
- for (UpdateListener listener : listeners.get(userId)) {
- listener.onUpdateEvent(event);
- }
- }
- }
-
- public interface UpdateListener {
- void onKeepalive();
- void onUpdateDevice(Device device);
- void onUpdatePosition(Position position);
- void onUpdateEvent(Event event);
- }
-
- public synchronized void addListener(long userId, UpdateListener listener) {
- if (!listeners.containsKey(userId)) {
- listeners.put(userId, new HashSet<>());
- }
- listeners.get(userId).add(listener);
- }
-
- public synchronized void removeListener(long userId, UpdateListener listener) {
- if (!listeners.containsKey(userId)) {
- listeners.put(userId, new HashSet<>());
- }
- listeners.get(userId).remove(listener);
- }
-
-}
diff --git a/src/main/java/org/traccar/database/DataManager.java b/src/main/java/org/traccar/database/DataManager.java
deleted file mode 100644
index 9ac808a69..000000000
--- a/src/main/java/org/traccar/database/DataManager.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.traccar.database;
-
-import com.zaxxer.hikari.HikariConfig;
-import com.zaxxer.hikari.HikariDataSource;
-import liquibase.Contexts;
-import liquibase.Liquibase;
-import liquibase.database.Database;
-import liquibase.database.DatabaseFactory;
-import liquibase.exception.LiquibaseException;
-import liquibase.resource.FileSystemResourceAccessor;
-import liquibase.resource.ResourceAccessor;
-import org.traccar.Context;
-import org.traccar.config.Config;
-import org.traccar.config.Keys;
-import org.traccar.model.BaseModel;
-import org.traccar.model.Device;
-import org.traccar.model.Event;
-import org.traccar.model.Permission;
-import org.traccar.model.Position;
-import org.traccar.model.Server;
-import org.traccar.model.Statistics;
-import org.traccar.model.User;
-import org.traccar.storage.DatabaseStorage;
-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.sql.DataSource;
-import java.io.File;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.util.Collection;
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-
-public class DataManager {
-
- private final Config config;
-
- private DataSource dataSource;
-
- public DataSource getDataSource() {
- return dataSource;
- }
-
- private final Storage storage;
-
- public Storage getStorage() {
- return storage;
- }
-
- private final boolean forceLdap;
-
- public DataManager(Config config) throws Exception {
- this.config = config;
-
- forceLdap = config.getBoolean(Keys.LDAP_FORCE);
-
- initDatabase();
- initDatabaseSchema();
-
- storage = new DatabaseStorage(dataSource);
- }
-
- private void initDatabase() throws Exception {
-
- String driverFile = config.getString(Keys.DATABASE_DRIVER_FILE);
- if (driverFile != null) {
- ClassLoader classLoader = ClassLoader.getSystemClassLoader();
- try {
- Method method = classLoader.getClass().getDeclaredMethod("addURL", URL.class);
- method.setAccessible(true);
- method.invoke(classLoader, new File(driverFile).toURI().toURL());
- } catch (NoSuchMethodException e) {
- Method method = classLoader.getClass()
- .getDeclaredMethod("appendToClassPathForInstrumentation", String.class);
- method.setAccessible(true);
- method.invoke(classLoader, driverFile);
- }
- }
-
- String driver = config.getString(Keys.DATABASE_DRIVER);
- if (driver != null) {
- Class.forName(driver);
- }
-
- HikariConfig hikariConfig = new HikariConfig();
- hikariConfig.setDriverClassName(driver);
- hikariConfig.setJdbcUrl(config.getString(Keys.DATABASE_URL));
- hikariConfig.setUsername(config.getString(Keys.DATABASE_USER));
- hikariConfig.setPassword(config.getString(Keys.DATABASE_PASSWORD));
- hikariConfig.setConnectionInitSql(config.getString(Keys.DATABASE_CHECK_CONNECTION));
- hikariConfig.setIdleTimeout(600000);
-
- int maxPoolSize = config.getInteger(Keys.DATABASE_MAX_POOL_SIZE);
- if (maxPoolSize != 0) {
- hikariConfig.setMaximumPoolSize(maxPoolSize);
- }
-
- dataSource = new HikariDataSource(hikariConfig);
- }
-
- private void initDatabaseSchema() throws LiquibaseException {
-
- if (config.hasKey(Keys.DATABASE_CHANGELOG)) {
-
- ResourceAccessor resourceAccessor = new FileSystemResourceAccessor(new File("."));
-
- Database database = DatabaseFactory.getInstance().openDatabase(
- config.getString(Keys.DATABASE_URL),
- config.getString(Keys.DATABASE_USER),
- config.getString(Keys.DATABASE_PASSWORD),
- config.getString(Keys.DATABASE_DRIVER),
- null, null, null, resourceAccessor);
-
- Liquibase liquibase = new Liquibase(
- config.getString(Keys.DATABASE_CHANGELOG), resourceAccessor, database);
-
- liquibase.clearCheckSums();
-
- liquibase.update(new Contexts());
- }
- }
-
- public User login(String email, String password) throws StorageException {
- User user = storage.getObject(User.class, new Request(
- new Columns.Include("id", "login", "hashedPassword", "salt"),
- new Condition.Or(
- new Condition.Equals("email", "email", email.trim()),
- new Condition.Equals("login", "email"))));
- LdapProvider ldapProvider = Context.getLdapProvider();
- if (user != null) {
- if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password)
- || !forceLdap && user.isPasswordValid(password)) {
- return user;
- }
- } else {
- if (ldapProvider != null && ldapProvider.login(email, password)) {
- user = ldapProvider.getUser(email);
- Context.getUsersManager().addItem(user);
- return user;
- }
- }
- return null;
- }
-
- public void updateUserPassword(User user) throws StorageException {
- storage.updateObject(user, new Request(
- new Columns.Include("hashedPassword", "salt"),
- new Condition.Equals("id", "id")));
- }
-
- public void updateDeviceStatus(Device device) throws StorageException {
- storage.updateObject(device, new Request(
- new Columns.Include("lastUpdate"),
- new Condition.Equals("id", "id")));
- }
-
- public Collection<Position> getPositions(long deviceId, Date from, Date to) throws StorageException {
- return storage.getObjects(Position.class, new Request(
- new Columns.All(),
- new Condition.And(
- new Condition.Equals("deviceId", "deviceId", deviceId),
- new Condition.Between("fixTime", "from", from, "to", to)),
- new Order("fixTime")));
- }
-
- public 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)));
- }
-
- public void updateLatestPosition(Position position) throws StorageException {
- Device device = new Device();
- device.setId(position.getDeviceId());
- device.setPositionId(position.getId());
- storage.updateObject(device, new Request(
- new Columns.Include("positionId"),
- new Condition.Equals("id", "id")));
- }
-
- public Collection<Position> getLatestPositions() throws StorageException {
- List<Position> positions = new LinkedList<>();
- List<Device> devices = storage.getObjects(Device.class, new Request(new Columns.Include("positionId")));
- for (Device device : devices) {
- positions.addAll(storage.getObjects(Position.class, new Request(
- new Columns.All(),
- new Condition.Equals("id", "id", device.getPositionId()))));
- }
- return positions;
- }
-
- public Server getServer() throws StorageException {
- return storage.getObject(Server.class, new Request(new Columns.All()));
- }
-
- public Collection<Event> getEvents(long deviceId, Date from, Date to) throws StorageException {
- return storage.getObjects(Event.class, new Request(
- new Columns.All(),
- new Condition.And(
- new Condition.Equals("deviceId", "deviceId", deviceId),
- new Condition.Between("eventTime", "from", from, "to", to)),
- new Order("eventTime")));
- }
-
- public Collection<Statistics> getStatistics(Date from, Date to) throws StorageException {
- return storage.getObjects(Statistics.class, new Request(
- new Columns.All(),
- new Condition.Between("captureTime", "from", from, "to", to),
- new Order("captureTime")));
- }
-
- public Collection<Permission> getPermissions(Class<? extends BaseModel> owner, Class<? extends BaseModel> property)
- throws StorageException, ClassNotFoundException {
- return storage.getPermissions(owner, property);
- }
-
- public void linkObject(Class<?> owner, long ownerId, Class<?> property, long propertyId, boolean link)
- throws StorageException {
- if (link) {
- storage.addPermission(new Permission(owner, ownerId, property, propertyId));
- } else {
- storage.removePermission(new Permission(owner, ownerId, property, propertyId));
- }
- }
-
- public <T extends BaseModel> T getObject(Class<T> clazz, long entityId) throws StorageException {
- return storage.getObject(clazz, new Request(
- new Columns.All(),
- new Condition.Equals("id", "id", entityId)));
- }
-
- public <T extends BaseModel> Collection<T> getObjects(Class<T> clazz) throws StorageException {
- return storage.getObjects(clazz, new Request(new Columns.All()));
- }
-
- public void addObject(BaseModel entity) throws StorageException {
- entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id"))));
- }
-
- public void updateObject(BaseModel entity) throws StorageException {
- storage.updateObject(entity, new Request(
- new Columns.Exclude("id"),
- new Condition.Equals("id", "id")));
- }
-
- public void removeObject(Class<? extends BaseModel> clazz, long entityId) throws StorageException {
- storage.removeObject(clazz, new Request(new Condition.Equals("id", "id", entityId)));
- }
-
-}
diff --git a/src/main/java/org/traccar/database/DeviceLookupService.java b/src/main/java/org/traccar/database/DeviceLookupService.java
new file mode 100644
index 000000000..6ec6841a1
--- /dev/null
+++ b/src/main/java/org/traccar/database/DeviceLookupService.java
@@ -0,0 +1,141 @@
+/*
+ * 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.database;
+
+import io.netty.util.Timeout;
+import io.netty.util.Timer;
+import io.netty.util.TimerTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.model.Device;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+@Singleton
+public class DeviceLookupService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DeviceLookupService.class);
+
+ private static final long INFO_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(60);
+ private static final long THROTTLE_MIN_MS = TimeUnit.MINUTES.toMillis(1);
+ private static final long THROTTLE_MAX_MS = TimeUnit.MINUTES.toMillis(30);
+
+ private final Storage storage;
+ private final Timer timer;
+
+ private final boolean throttlingEnabled;
+
+ private static class IdentifierInfo {
+ private long lastQuery;
+ private long delay;
+ private Timeout timeout;
+ }
+
+ private final class IdentifierTask implements TimerTask {
+ private final String uniqueId;
+
+ private IdentifierTask(String uniqueId) {
+ this.uniqueId = uniqueId;
+ }
+
+ @Override
+ public void run(Timeout timeout) {
+ LOGGER.debug("Device lookup expired {}", uniqueId);
+ synchronized (DeviceLookupService.this) {
+ identifierMap.remove(uniqueId);
+ }
+ }
+ }
+
+ private final Map<String, IdentifierInfo> identifierMap = new ConcurrentHashMap<>();
+
+ @Inject
+ public DeviceLookupService(Config config, Storage storage, Timer timer) {
+ this.storage = storage;
+ this.timer = timer;
+ throttlingEnabled = config.getBoolean(Keys.DATABASE_THROTTLE_UNKNOWN);
+ }
+
+ private synchronized boolean isThrottled(String uniqueId) {
+ if (throttlingEnabled) {
+ IdentifierInfo info = identifierMap.get(uniqueId);
+ return info != null && System.currentTimeMillis() < info.lastQuery + info.delay;
+ } else {
+ return false;
+ }
+ }
+
+ private synchronized void lookupSucceeded(String uniqueId) {
+ if (throttlingEnabled) {
+ IdentifierInfo info = identifierMap.remove(uniqueId);
+ if (info != null) {
+ info.timeout.cancel();
+ }
+ }
+ }
+
+ private synchronized void lookupFailed(String uniqueId) {
+ if (throttlingEnabled) {
+ IdentifierInfo info = identifierMap.get(uniqueId);
+ if (info != null) {
+ info.timeout.cancel();
+ info.delay = Math.min(info.delay * 2, THROTTLE_MAX_MS);
+ } else {
+ info = new IdentifierInfo();
+ identifierMap.put(uniqueId, info);
+ info.delay = THROTTLE_MIN_MS;
+ }
+ info.lastQuery = System.currentTimeMillis();
+ info.timeout = timer.newTimeout(new IdentifierTask(uniqueId), INFO_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ LOGGER.debug("Device lookup {} throttled for {} ms", uniqueId, info.delay);
+ }
+ }
+
+ public Device lookup(String[] uniqueIds) {
+ Device device = null;
+ try {
+ for (String uniqueId : uniqueIds) {
+ if (!isThrottled(uniqueId)) {
+ device = storage.getObject(Device.class, new Request(
+ new Columns.All(), new Condition.Equals("uniqueId", uniqueId)));
+ if (device != null) {
+ lookupSucceeded(uniqueId);
+ break;
+ } else {
+ lookupFailed(uniqueId);
+ }
+ } else {
+ LOGGER.debug("Device lookup throttled {}", uniqueId);
+ }
+ }
+ } catch (StorageException e) {
+ LOGGER.warn("Find device error", e);
+ }
+ return device;
+ }
+
+}
diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java
deleted file mode 100644
index 40591e869..000000000
--- a/src/main/java/org/traccar/database/DeviceManager.java
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * Copyright 2016 - 2020 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.database;
-
-import java.sql.SQLException;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.config.Config;
-import org.traccar.Context;
-import org.traccar.config.Keys;
-import org.traccar.model.Command;
-import org.traccar.model.Device;
-import org.traccar.model.DeviceState;
-import org.traccar.model.DeviceAccumulators;
-import org.traccar.model.Group;
-import org.traccar.model.Position;
-import org.traccar.model.Server;
-import org.traccar.storage.StorageException;
-
-public class DeviceManager extends BaseObjectManager<Device> implements IdentityManager, ManagableObjects {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(DeviceManager.class);
-
- private final Config config;
- private final long dataRefreshDelay;
-
- private Map<String, Device> devicesByUniqueId;
- private Map<String, Device> devicesByPhone;
- private final AtomicLong devicesLastUpdate = new AtomicLong();
-
- private final Map<Long, Position> positions = new ConcurrentHashMap<>();
-
- private final Map<Long, DeviceState> deviceStates = new ConcurrentHashMap<>();
-
- public DeviceManager(DataManager dataManager) {
- super(dataManager, Device.class);
- this.config = Context.getConfig();
- try {
- writeLock();
- if (devicesByPhone == null) {
- devicesByPhone = new ConcurrentHashMap<>();
- }
- if (devicesByUniqueId == null) {
- devicesByUniqueId = new ConcurrentHashMap<>();
- }
- } finally {
- writeUnlock();
- }
- dataRefreshDelay = config.getLong(Keys.DATABASE_REFRESH_DELAY) * 1000;
- refreshLastPositions();
- }
-
- @Override
- public long 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();
- Context.getPermissionsManager().refreshAllExtendedPermissions();
- }
-
- return device.getId();
- } catch (StorageException e) {
- LOGGER.warn("Automatic device registration error", e);
- return 0;
- }
- }
-
- public void updateDeviceCache(boolean force) {
- long lastUpdate = devicesLastUpdate.get();
- if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay)
- && devicesLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) {
- refreshItems();
- }
- }
-
- @Override
- public Device getByUniqueId(String uniqueId) throws SQLException {
- boolean forceUpdate;
- try {
- readLock();
- forceUpdate = !devicesByUniqueId.containsKey(uniqueId) && !config.getBoolean(Keys.DATABASE_IGNORE_UNKNOWN);
- } finally {
- readUnlock();
- }
- updateDeviceCache(forceUpdate);
- try {
- readLock();
- return devicesByUniqueId.get(uniqueId);
- } finally {
- readUnlock();
- }
- }
-
- @Override
- public String getDevicePassword(long id, String protocol, String defaultPassword) {
-
- String password = lookupAttributeString(id, Command.KEY_DEVICE_PASSWORD, null, false, false);
- if (password != null) {
- return password;
- }
-
- if (protocol != null) {
- password = Context.getConfig().getString(Keys.PROTOCOL_DEVICE_PASSWORD.withPrefix(protocol));
- if (password != null) {
- return password;
- }
- }
-
- return defaultPassword;
- }
-
- @Override
- public Set<Long> getAllItems() {
- Set<Long> result = super.getAllItems();
- if (result.isEmpty()) {
- updateDeviceCache(true);
- result = super.getAllItems();
- }
- return result;
- }
-
- public Collection<Device> getAllDevices() {
- return getItems(getAllItems());
- }
-
- public Set<Long> getAllUserItems(long userId) {
- return Context.getPermissionsManager().getDevicePermissions(userId);
- }
-
- @Override
- public Set<Long> getUserItems(long userId) {
- if (Context.getPermissionsManager() != null) {
- Set<Long> result = new HashSet<>();
- for (long deviceId : Context.getPermissionsManager().getDevicePermissions(userId)) {
- Device device = getById(deviceId);
- if (device != null && !device.getDisabled()) {
- result.add(deviceId);
- }
- }
- return result;
- } else {
- return new HashSet<>();
- }
- }
-
- public Set<Long> getAllManagedItems(long userId) {
- Set<Long> result = new HashSet<>(getAllUserItems(userId));
- for (long managedUserId : Context.getUsersManager().getUserItems(userId)) {
- result.addAll(getAllUserItems(managedUserId));
- }
- return result;
- }
-
- @Override
- public Set<Long> getManagedItems(long userId) {
- Set<Long> result = new HashSet<>(getUserItems(userId));
- for (long managedUserId : Context.getUsersManager().getUserItems(userId)) {
- result.addAll(getUserItems(managedUserId));
- }
- return result;
- }
-
- private void addByUniqueId(Device device) {
- try {
- writeLock();
- if (devicesByUniqueId == null) {
- devicesByUniqueId = new ConcurrentHashMap<>();
- }
- devicesByUniqueId.put(device.getUniqueId(), device);
- } finally {
- writeUnlock();
- }
- }
-
- private void removeByUniqueId(String deviceUniqueId) {
- try {
- writeLock();
- if (devicesByUniqueId != null) {
- devicesByUniqueId.remove(deviceUniqueId);
- }
- } finally {
- writeUnlock();
- }
- }
-
- private void addByPhone(Device device) {
- try {
- writeLock();
- if (devicesByPhone == null) {
- devicesByPhone = new ConcurrentHashMap<>();
- }
- devicesByPhone.put(device.getPhone(), device);
- } finally {
- writeUnlock();
- }
- }
-
- private void removeByPhone(String phone) {
- if (phone == null || phone.isEmpty()) {
- return;
- }
- try {
- writeLock();
- if (devicesByPhone != null) {
- devicesByPhone.remove(phone);
- }
- } finally {
- writeUnlock();
- }
- }
-
- @Override
- protected void addNewItem(Device device) {
- super.addNewItem(device);
- addByUniqueId(device);
- if (device.getPhone() != null && !device.getPhone().isEmpty()) {
- addByPhone(device);
- }
- if (Context.getGeofenceManager() != null) {
- Position lastPosition = getLastPosition(device.getId());
- if (lastPosition != null) {
- device.setGeofenceIds(Context.getGeofenceManager().getCurrentDeviceGeofences(lastPosition));
- }
- }
- }
-
- @Override
- protected void updateCachedItem(Device device) {
- Device cachedDevice = getById(device.getId());
- cachedDevice.setName(device.getName());
- cachedDevice.setGroupId(device.getGroupId());
- cachedDevice.setCategory(device.getCategory());
- cachedDevice.setContact(device.getContact());
- cachedDevice.setModel(device.getModel());
- cachedDevice.setDisabled(device.getDisabled());
- cachedDevice.setAttributes(device.getAttributes());
- if (!device.getUniqueId().equals(cachedDevice.getUniqueId())) {
- removeByUniqueId(cachedDevice.getUniqueId());
- cachedDevice.setUniqueId(device.getUniqueId());
- addByUniqueId(cachedDevice);
- }
- if (device.getPhone() != null && !device.getPhone().isEmpty()
- && !device.getPhone().equals(cachedDevice.getPhone())) {
- String phone = cachedDevice.getPhone();
- removeByPhone(phone);
- cachedDevice.setPhone(device.getPhone());
- addByPhone(cachedDevice);
- }
- }
-
- @Override
- protected void removeCachedItem(long deviceId) {
- Device cachedDevice = getById(deviceId);
- if (cachedDevice != null) {
- String deviceUniqueId = cachedDevice.getUniqueId();
- String phone = cachedDevice.getPhone();
- super.removeCachedItem(deviceId);
- removeByUniqueId(deviceUniqueId);
- removeByPhone(phone);
- }
- positions.remove(deviceId);
- }
-
- public void updateDeviceStatus(Device device) throws StorageException {
- getDataManager().updateDeviceStatus(device);
- Device cachedDevice = getById(device.getId());
- if (cachedDevice != null) {
- cachedDevice.setStatus(device.getStatus());
- }
- }
-
- private void refreshLastPositions() {
- if (getDataManager() != null) {
- try {
- for (Position position : getDataManager().getLatestPositions()) {
- positions.put(position.getDeviceId(), position);
- }
- } catch (StorageException error) {
- LOGGER.warn("Load latest positions error", error);
- }
- }
- }
-
- public boolean isLatestPosition(Position position) {
- Position lastPosition = getLastPosition(position.getDeviceId());
- return lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) >= 0;
- }
-
- public void updateLatestPosition(Position position) throws StorageException {
-
- if (isLatestPosition(position)) {
-
- getDataManager().updateLatestPosition(position);
-
- Device device = getById(position.getDeviceId());
- if (device != null) {
- device.setPositionId(position.getId());
- }
-
- positions.put(position.getDeviceId(), position);
-
- if (Context.getConnectionManager() != null) {
- Context.getConnectionManager().updatePosition(position);
- }
- }
- }
-
- @Override
- public Position getLastPosition(long deviceId) {
- return positions.get(deviceId);
- }
-
- public Collection<Position> getInitialState(long userId) {
-
- List<Position> result = new LinkedList<>();
-
- if (Context.getPermissionsManager() != null) {
- for (long deviceId : Context.getPermissionsManager().getUserAdmin(userId)
- ? getAllUserItems(userId) : getUserItems(userId)) {
- if (positions.containsKey(deviceId)) {
- result.add(positions.get(deviceId));
- }
- }
- }
-
- return result;
- }
-
- @Override
- public boolean lookupAttributeBoolean(
- long deviceId, String attributeName, boolean defaultValue, boolean lookupServer, boolean lookupConfig) {
- Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig);
- if (result != null) {
- return result instanceof String ? Boolean.parseBoolean((String) result) : (Boolean) result;
- }
- return defaultValue;
- }
-
- @Override
- public String lookupAttributeString(
- long deviceId, String attributeName, String defaultValue, boolean lookupServer, boolean lookupConfig) {
- Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig);
- 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);
- if (device != null) {
- result = device.getAttributes().get(attributeName);
- if (result == null) {
- long groupId = device.getGroupId();
- while (groupId != 0) {
- Group group = Context.getGroupsManager().getById(groupId);
- if (group != null) {
- result = group.getAttributes().get(attributeName);
- if (result != null) {
- break;
- }
- groupId = group.getGroupId();
- } else {
- groupId = 0;
- }
- }
- }
- if (result == null && lookupServer) {
- Server server = Context.getPermissionsManager().getServer();
- result = server.getAttributes().get(attributeName);
- }
- if (result == null && lookupConfig) {
- result = Context.getConfig().getString(attributeName);
- }
- }
- return result;
- }
-
- public void resetDeviceAccumulators(DeviceAccumulators deviceAccumulators) throws StorageException {
- Position last = positions.get(deviceAccumulators.getDeviceId());
- if (last != null) {
- if (deviceAccumulators.getTotalDistance() != null) {
- last.getAttributes().put(Position.KEY_TOTAL_DISTANCE, deviceAccumulators.getTotalDistance());
- }
- if (deviceAccumulators.getHours() != null) {
- last.getAttributes().put(Position.KEY_HOURS, deviceAccumulators.getHours());
- }
- getDataManager().addObject(last);
- updateLatestPosition(last);
- } else {
- throw new IllegalArgumentException();
- }
- }
-
- public DeviceState getDeviceState(long deviceId) {
- DeviceState deviceState = deviceStates.get(deviceId);
- if (deviceState == null) {
- deviceState = new DeviceState();
- deviceStates.put(deviceId, deviceState);
- }
- return deviceState;
- }
-
- public void setDeviceState(long deviceId, DeviceState deviceState) {
- deviceStates.put(deviceId, deviceState);
- }
-
-}
diff --git a/src/main/java/org/traccar/database/DriversManager.java b/src/main/java/org/traccar/database/DriversManager.java
deleted file mode 100644
index d111cd643..000000000
--- a/src/main/java/org/traccar/database/DriversManager.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.database;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.traccar.model.Driver;
-
-public class DriversManager extends ExtendedObjectManager<Driver> {
-
- private Map<String, Driver> driversByUniqueId;
-
- public DriversManager(DataManager dataManager) {
- super(dataManager, Driver.class);
- try {
- writeLock();
- if (driversByUniqueId == null) {
- driversByUniqueId = new ConcurrentHashMap<>();
- }
- } finally {
- writeUnlock();
- }
- }
-
- private void addByUniqueId(Driver driver) {
- try {
- writeLock();
- if (driversByUniqueId == null) {
- driversByUniqueId = new ConcurrentHashMap<>();
- }
- driversByUniqueId.put(driver.getUniqueId(), driver);
- } finally {
- writeUnlock();
- }
- }
-
- private void removeByUniqueId(String driverUniqueId) {
- try {
- writeLock();
- if (driversByUniqueId == null) {
- driversByUniqueId = new ConcurrentHashMap<>();
- }
- driversByUniqueId.remove(driverUniqueId);
- } finally {
- writeUnlock();
- }
- }
-
- @Override
- protected void addNewItem(Driver driver) {
- super.addNewItem(driver);
- addByUniqueId(driver);
- }
-
- @Override
- protected void updateCachedItem(Driver driver) {
- Driver cachedDriver = getById(driver.getId());
- cachedDriver.setName(driver.getName());
- if (!driver.getUniqueId().equals(cachedDriver.getUniqueId())) {
- removeByUniqueId(cachedDriver.getUniqueId());
- cachedDriver.setUniqueId(driver.getUniqueId());
- addByUniqueId(cachedDriver);
- }
- cachedDriver.setAttributes(driver.getAttributes());
- }
-
- @Override
- protected void removeCachedItem(long driverId) {
- Driver cachedDriver = getById(driverId);
- if (cachedDriver != null) {
- String driverUniqueId = cachedDriver.getUniqueId();
- super.removeCachedItem(driverId);
- removeByUniqueId(driverUniqueId);
- }
- }
-
- public Driver getDriverByUniqueId(String uniqueId) {
- try {
- readLock();
- return driversByUniqueId.get(uniqueId);
- } finally {
- readUnlock();
- }
- }
-}
diff --git a/src/main/java/org/traccar/database/ExtendedObjectManager.java b/src/main/java/org/traccar/database/ExtendedObjectManager.java
deleted file mode 100644
index 006ed47b2..000000000
--- a/src/main/java/org/traccar/database/ExtendedObjectManager.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.database;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.model.Device;
-import org.traccar.model.Group;
-import org.traccar.model.Permission;
-import org.traccar.model.BaseModel;
-import org.traccar.storage.StorageException;
-
-public abstract class ExtendedObjectManager<T extends BaseModel> extends SimpleObjectManager<T> {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(ExtendedObjectManager.class);
-
- private final Map<Long, Set<Long>> deviceItems = new ConcurrentHashMap<>();
- private final Map<Long, Set<Long>> deviceItemsWithGroups = new ConcurrentHashMap<>();
- private final Map<Long, Set<Long>> groupItems = new ConcurrentHashMap<>();
-
- protected ExtendedObjectManager(DataManager dataManager, Class<T> baseClass) {
- super(dataManager, baseClass);
- refreshExtendedPermissions();
- }
-
- public final Set<Long> getGroupItems(long groupId) {
- try {
- readLock();
- Set<Long> result = groupItems.get(groupId);
- if (result != null) {
- return new HashSet<>(result);
- } else {
- return new HashSet<>();
- }
- } finally {
- readUnlock();
- }
- }
-
- public final Set<Long> getDeviceItems(long deviceId) {
- try {
- readLock();
- Set<Long> result = deviceItems.get(deviceId);
- if (result != null) {
- return new HashSet<>(result);
- } else {
- return new HashSet<>();
- }
- } finally {
- readUnlock();
- }
- }
-
- public Set<Long> getAllDeviceItems(long deviceId) {
- try {
- readLock();
- Set<Long> result = deviceItemsWithGroups.get(deviceId);
- if (result != null) {
- return new HashSet<>(result);
- } else {
- return new HashSet<>();
- }
- } finally {
- readUnlock();
- }
- }
-
- @Override
- public void removeItem(long itemId) throws StorageException {
- super.removeItem(itemId);
- refreshExtendedPermissions();
- }
-
- public void refreshExtendedPermissions() {
- if (getDataManager() != null) {
- try {
- Collection<Permission> databaseGroupPermissions =
- getDataManager().getPermissions(Group.class, getBaseClass());
-
- Collection<Permission> databaseDevicePermissions =
- getDataManager().getPermissions(Device.class, getBaseClass());
-
- writeLock();
-
- groupItems.clear();
- deviceItems.clear();
- deviceItemsWithGroups.clear();
-
- for (Permission groupPermission : databaseGroupPermissions) {
- groupItems
- .computeIfAbsent(groupPermission.getOwnerId(), key -> new HashSet<>())
- .add(groupPermission.getPropertyId());
- }
-
- for (Permission devicePermission : databaseDevicePermissions) {
- deviceItems
- .computeIfAbsent(devicePermission.getOwnerId(), key -> new HashSet<>())
- .add(devicePermission.getPropertyId());
- deviceItemsWithGroups
- .computeIfAbsent(devicePermission.getOwnerId(), key -> new HashSet<>())
- .add(devicePermission.getPropertyId());
- }
-
- for (Device device : Context.getDeviceManager().getAllDevices()) {
- long groupId = device.getGroupId();
- while (groupId > 0) {
- deviceItemsWithGroups
- .computeIfAbsent(device.getId(), key -> new HashSet<>())
- .addAll(groupItems.getOrDefault(groupId, new HashSet<>()));
- Group group = Context.getGroupsManager().getById(groupId);
- groupId = group != null ? group.getGroupId() : 0;
- }
- }
-
- } catch (StorageException | ClassNotFoundException error) {
- LOGGER.warn("Refresh permissions error", error);
- } finally {
- writeUnlock();
- }
- }
- }
-}
diff --git a/src/main/java/org/traccar/database/GeofenceManager.java b/src/main/java/org/traccar/database/GeofenceManager.java
deleted file mode 100644
index a32847cf9..000000000
--- a/src/main/java/org/traccar/database/GeofenceManager.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2016 - 2017 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.database;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.traccar.Context;
-import org.traccar.model.Device;
-import org.traccar.model.Geofence;
-import org.traccar.model.Position;
-
-public class GeofenceManager extends ExtendedObjectManager<Geofence> {
-
- public GeofenceManager(DataManager dataManager) {
- super(dataManager, Geofence.class);
- }
-
- @Override
- public final void refreshExtendedPermissions() {
- super.refreshExtendedPermissions();
- recalculateDevicesGeofences();
- }
-
- public List<Long> getCurrentDeviceGeofences(Position position) {
- List<Long> result = new ArrayList<>();
- for (long geofenceId : getAllDeviceItems(position.getDeviceId())) {
- Geofence geofence = getById(geofenceId);
- if (geofence != null && geofence.getGeometry()
- .containsPoint(position.getLatitude(), position.getLongitude())) {
- result.add(geofenceId);
- }
- }
- return result;
- }
-
- public void recalculateDevicesGeofences() {
- for (Device device : Context.getDeviceManager().getAllDevices()) {
- List<Long> deviceGeofenceIds = device.getGeofenceIds();
- if (deviceGeofenceIds == null) {
- deviceGeofenceIds = new ArrayList<>();
- } else {
- deviceGeofenceIds.clear();
- }
- Position lastPosition = Context.getIdentityManager().getLastPosition(device.getId());
- if (lastPosition != null && getAllDeviceItems(device.getId()) != null) {
- deviceGeofenceIds.addAll(getCurrentDeviceGeofences(lastPosition));
- }
- device.setGeofenceIds(deviceGeofenceIds);
- }
- }
-
-}
diff --git a/src/main/java/org/traccar/database/GroupsManager.java b/src/main/java/org/traccar/database/GroupsManager.java
deleted file mode 100644
index dafddc0cc..000000000
--- a/src/main/java/org/traccar/database/GroupsManager.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.database;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import org.traccar.Context;
-import org.traccar.model.Group;
-import org.traccar.storage.StorageException;
-
-public class GroupsManager extends BaseObjectManager<Group> implements ManagableObjects {
-
- public GroupsManager(DataManager dataManager) {
- super(dataManager, Group.class);
- }
-
- private void checkGroupCycles(Group group) {
- Set<Long> groups = new HashSet<>();
- while (group != null) {
- if (groups.contains(group.getId())) {
- throw new IllegalArgumentException("Cycle in group hierarchy");
- }
- groups.add(group.getId());
- group = getById(group.getGroupId());
- }
- }
-
- @Override
- public Set<Long> getAllItems() {
- Set<Long> result = super.getAllItems();
- if (result.isEmpty()) {
- refreshItems();
- result = super.getAllItems();
- }
- return result;
- }
-
- @Override
- protected void addNewItem(Group group) {
- checkGroupCycles(group);
- super.addNewItem(group);
- }
-
- @Override
- public void updateItem(Group group) throws StorageException {
- checkGroupCycles(group);
- super.updateItem(group);
- }
-
- @Override
- public Set<Long> getUserItems(long userId) {
- if (Context.getPermissionsManager() != null) {
- return Context.getPermissionsManager().getGroupPermissions(userId);
- } else {
- return new HashSet<>();
- }
- }
-
- @Override
- public Set<Long> getManagedItems(long userId) {
- Set<Long> result = getUserItems(userId);
- for (long managedUserId : Context.getUsersManager().getUserItems(userId)) {
- result.addAll(getUserItems(managedUserId));
- }
- return result;
- }
-
-}
diff --git a/src/main/java/org/traccar/database/IdentityManager.java b/src/main/java/org/traccar/database/IdentityManager.java
deleted file mode 100644
index af6a6ce71..000000000
--- a/src/main/java/org/traccar/database/IdentityManager.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2015 - 2019 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.database;
-
-import org.traccar.model.Device;
-import org.traccar.model.Position;
-
-public interface IdentityManager {
-
- long addUnknownDevice(String uniqueId);
-
- Device getById(long id);
-
- Device getByUniqueId(String uniqueId) throws Exception;
-
- String getDevicePassword(long id, String protocol, String defaultPassword);
-
- Position getLastPosition(long deviceId);
-
- boolean isLatestPosition(Position position);
-
- boolean lookupAttributeBoolean(
- long deviceId, String attributeName, boolean defaultValue, boolean lookupServer, boolean lookupConfig);
-
- 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/database/LdapProvider.java b/src/main/java/org/traccar/database/LdapProvider.java
index d659a11a1..d517294b8 100644
--- a/src/main/java/org/traccar/database/LdapProvider.java
+++ b/src/main/java/org/traccar/database/LdapProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2020 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.
diff --git a/src/main/java/org/traccar/database/MailManager.java b/src/main/java/org/traccar/database/MailManager.java
deleted file mode 100644
index d94f55cda..000000000
--- a/src/main/java/org/traccar/database/MailManager.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@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.database;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.Main;
-import org.traccar.model.User;
-import org.traccar.notification.PropertiesProvider;
-
-import javax.mail.BodyPart;
-import javax.mail.Message;
-import javax.mail.MessagingException;
-import javax.mail.Multipart;
-import javax.mail.Session;
-import javax.mail.Transport;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeBodyPart;
-import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeMultipart;
-import java.util.Date;
-import java.util.Properties;
-
-public final class MailManager {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(MailManager.class);
-
- private static Properties getProperties(PropertiesProvider provider) {
- Properties properties = new Properties();
- String host = provider.getString("mail.smtp.host");
- if (host != null) {
- properties.put("mail.transport.protocol", provider.getString("mail.transport.protocol", "smtp"));
- properties.put("mail.smtp.host", host);
- properties.put("mail.smtp.port", String.valueOf(provider.getInteger("mail.smtp.port", 25)));
-
- Boolean starttlsEnable = provider.getBoolean("mail.smtp.starttls.enable");
- if (starttlsEnable != null) {
- properties.put("mail.smtp.starttls.enable", String.valueOf(starttlsEnable));
- }
- Boolean starttlsRequired = provider.getBoolean("mail.smtp.starttls.required");
- if (starttlsRequired != null) {
- properties.put("mail.smtp.starttls.required", String.valueOf(starttlsRequired));
- }
-
- Boolean sslEnable = provider.getBoolean("mail.smtp.ssl.enable");
- if (sslEnable != null) {
- properties.put("mail.smtp.ssl.enable", String.valueOf(sslEnable));
- }
- String sslTrust = provider.getString("mail.smtp.ssl.trust");
- if (sslTrust != null) {
- properties.put("mail.smtp.ssl.trust", sslTrust);
- }
-
- String sslProtocols = provider.getString("mail.smtp.ssl.protocols");
- if (sslProtocols != null) {
- properties.put("mail.smtp.ssl.protocols", sslProtocols);
- }
-
- String username = provider.getString("mail.smtp.username");
- if (username != null) {
- properties.put("mail.smtp.username", username);
- }
- String password = provider.getString("mail.smtp.password");
- if (password != null) {
- properties.put("mail.smtp.password", password);
- }
- String from = provider.getString("mail.smtp.from");
- if (from != null) {
- properties.put("mail.smtp.from", from);
- }
- }
- return properties;
- }
-
- public boolean getEmailEnabled() {
- return Context.getConfig().hasKey("mail.smtp.host");
- }
-
- public void sendMessage(
- long userId, String subject, String body) throws MessagingException {
- sendMessage(userId, subject, body, null);
- }
-
- public void sendMessage(
- long userId, String subject, String body, MimeBodyPart attachment) throws MessagingException {
- User user = Context.getPermissionsManager().getUser(userId);
-
- Properties properties = null;
- if (!Context.getConfig().getBoolean("mail.smtp.ignoreUserConfig")) {
- properties = getProperties(new PropertiesProvider(user));
- }
- if (properties == null || !properties.containsKey("mail.smtp.host")) {
- properties = getProperties(new PropertiesProvider(Context.getConfig()));
- }
- if (!properties.containsKey("mail.smtp.host")) {
- LOGGER.warn("No SMTP configuration found");
- return;
- }
-
- Session session = Session.getInstance(properties);
-
- MimeMessage message = new MimeMessage(session);
-
- String from = properties.getProperty("mail.smtp.from");
- if (from != null) {
- message.setFrom(new InternetAddress(from));
- }
-
- message.addRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail()));
- message.setSubject(subject);
- message.setSentDate(new Date());
-
- if (attachment != null) {
- Multipart multipart = new MimeMultipart();
-
- BodyPart messageBodyPart = new MimeBodyPart();
- messageBodyPart.setContent(body, "text/html; charset=utf-8");
- multipart.addBodyPart(messageBodyPart);
- multipart.addBodyPart(attachment);
-
- message.setContent(multipart);
- } else {
- message.setContent(body, "text/html; charset=utf-8");
- }
-
- try (Transport transport = session.getTransport()) {
- Main.getInjector().getInstance(StatisticsManager.class).registerMail();
- transport.connect(
- properties.getProperty("mail.smtp.host"),
- properties.getProperty("mail.smtp.username"),
- properties.getProperty("mail.smtp.password"));
- transport.sendMessage(message, message.getAllRecipients());
- }
- }
-
-}
diff --git a/src/main/java/org/traccar/database/MediaManager.java b/src/main/java/org/traccar/database/MediaManager.java
index edade5766..2f2369c96 100644
--- a/src/main/java/org/traccar/database/MediaManager.java
+++ b/src/main/java/org/traccar/database/MediaManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2018 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.
@@ -18,10 +18,15 @@ package org.traccar.database;
import io.netty.buffer.ByteBuf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
@@ -30,14 +35,16 @@ import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
+@Singleton
public class MediaManager {
private static final Logger LOGGER = LoggerFactory.getLogger(MediaManager.class);
- private String path;
+ private final String path;
- public MediaManager(String path) {
- this.path = path;
+ @Inject
+ public MediaManager(Config config) {
+ this.path = config.getString(Keys.MEDIA_PATH);
}
private File createFile(String uniqueId, String name) throws IOException {
@@ -49,6 +56,10 @@ public class MediaManager {
return filePath.toFile();
}
+ public OutputStream createFileStream(String uniqueId, String name, String extension) throws IOException {
+ return new FileOutputStream(createFile(uniqueId, name + "." + extension));
+ }
+
public String writeFile(String uniqueId, ByteBuf buf, String extension) {
if (path != null) {
int size = buf.readableBytes();
diff --git a/src/main/java/org/traccar/database/NotificationManager.java b/src/main/java/org/traccar/database/NotificationManager.java
index f358b1d4d..3a57788fb 100644
--- a/src/main/java/org/traccar/database/NotificationManager.java
+++ b/src/main/java/org/traccar/database/NotificationManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,128 +16,141 @@
*/
package org.traccar.database;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.Context;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
+import org.traccar.forward.EventData;
+import org.traccar.forward.EventForwarder;
+import org.traccar.geocoder.Geocoder;
import org.traccar.model.Calendar;
+import org.traccar.model.Device;
import org.traccar.model.Event;
+import org.traccar.model.Geofence;
+import org.traccar.model.Maintenance;
import org.traccar.model.Notification;
import org.traccar.model.Position;
-import org.traccar.model.Typed;
+import org.traccar.notification.MessageException;
+import org.traccar.notification.NotificatorManager;
+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.Request;
+
+import jakarta.annotation.Nullable;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
-public class NotificationManager extends ExtendedObjectManager<Notification> {
+@Singleton
+public class NotificationManager {
private static final Logger LOGGER = LoggerFactory.getLogger(NotificationManager.class);
- private final boolean geocodeOnRequest;
+ private final Storage storage;
+ private final CacheManager cacheManager;
+ private final EventForwarder eventForwarder;
+ private final NotificatorManager notificatorManager;
+ private final Geocoder geocoder;
- public NotificationManager(DataManager dataManager) {
- super(dataManager, Notification.class);
- geocodeOnRequest = Context.getConfig().getBoolean(Keys.GEOCODER_ON_REQUEST);
- }
+ private final boolean geocodeOnRequest;
- private Set<Long> getEffectiveNotifications(long userId, long deviceId, Date time) {
- Set<Long> result = new HashSet<>();
- Set<Long> deviceNotifications = getAllDeviceItems(deviceId);
- for (long itemId : getUserItems(userId)) {
- if (getById(itemId).getAlways() || deviceNotifications.contains(itemId)) {
- long calendarId = getById(itemId).getCalendarId();
- Calendar calendar = calendarId != 0 ? Context.getCalendarManager().getById(calendarId) : null;
- if (calendar == null || calendar.checkMoment(time)) {
- result.add(itemId);
- }
- }
- }
- return result;
+ @Inject
+ public NotificationManager(
+ Config config, Storage storage, CacheManager cacheManager, @Nullable EventForwarder eventForwarder,
+ NotificatorManager notificatorManager, @Nullable Geocoder geocoder) {
+ this.storage = storage;
+ this.cacheManager = cacheManager;
+ this.eventForwarder = eventForwarder;
+ this.notificatorManager = notificatorManager;
+ this.geocoder = geocoder;
+ geocodeOnRequest = config.getBoolean(Keys.GEOCODER_ON_REQUEST);
}
- public void updateEvent(Event event, Position position) {
+ private void updateEvent(Event event, Position position) {
try {
- getDataManager().addObject(event);
+ event.setId(storage.addObject(event, new Request(new Columns.Exclude("id"))));
} catch (StorageException error) {
LOGGER.warn("Event save error", error);
}
- long deviceId = event.getDeviceId();
- Set<Long> users = Context.getPermissionsManager().getDeviceUsers(deviceId);
- Set<Long> usersToForward = null;
- if (Context.getEventForwarder() != null) {
- usersToForward = new HashSet<>();
- }
- for (long userId : users) {
- if ((event.getGeofenceId() == 0
- || Context.getGeofenceManager().checkItemPermission(userId, event.getGeofenceId()))
- && (event.getMaintenanceId() == 0
- || Context.getMaintenancesManager().checkItemPermission(userId, event.getMaintenanceId()))) {
- if (usersToForward != null) {
- usersToForward.add(userId);
- }
- final Set<String> notificators = new HashSet<>();
- for (long notificationId : getEffectiveNotifications(userId, deviceId, event.getEventTime())) {
- Notification notification = getById(notificationId);
- if (getById(notificationId).getType().equals(event.getType())) {
- boolean filter = false;
- if (event.getType().equals(Event.TYPE_ALARM)) {
- String alarmsAttribute = notification.getString("alarms");
- if (alarmsAttribute == null) {
- filter = true;
- } else {
- List<String> alarms = Arrays.asList(alarmsAttribute.split(","));
- filter = !alarms.contains(event.getString(Position.KEY_ALARM));
- }
- }
- if (!filter) {
- notificators.addAll(notification.getNotificatorsTypes());
+ var notifications = cacheManager.getDeviceObjects(event.getDeviceId(), Notification.class).stream()
+ .filter(notification -> notification.getType().equals(event.getType()))
+ .filter(notification -> {
+ if (event.getType().equals(Event.TYPE_ALARM)) {
+ String alarmsAttribute = notification.getString("alarms");
+ if (alarmsAttribute != null) {
+ return Arrays.asList(alarmsAttribute.split(","))
+ .contains(event.getString(Position.KEY_ALARM));
}
+ return false;
}
- }
-
- if (position != null && position.getAddress() == null
- && geocodeOnRequest && Context.getGeocoder() != null) {
- position.setAddress(Context.getGeocoder()
- .getAddress(position.getLatitude(), position.getLongitude(), null));
- }
+ return true;
+ })
+ .filter(notification -> {
+ long calendarId = notification.getCalendarId();
+ Calendar calendar = calendarId != 0 ? cacheManager.getObject(Calendar.class, calendarId) : null;
+ return calendar == null || calendar.checkMoment(event.getEventTime());
+ })
+ .collect(Collectors.toUnmodifiableList());
- for (String notificator : notificators) {
- Context.getNotificatorManager().getNotificator(notificator).sendAsync(userId, event, position);
- }
+ if (!notifications.isEmpty()) {
+ if (position != null && position.getAddress() == null && geocodeOnRequest && geocoder != null) {
+ position.setAddress(geocoder.getAddress(position.getLatitude(), position.getLongitude(), null));
}
+
+ notifications.forEach(notification -> {
+ cacheManager.getNotificationUsers(notification.getId(), event.getDeviceId()).forEach(user -> {
+ for (String notificator : notification.getNotificatorsTypes()) {
+ try {
+ notificatorManager.getNotificator(notificator).send(notification, user, event, position);
+ } catch (MessageException exception) {
+ LOGGER.warn("Notification failed", exception);
+ }
+ }
+ });
+ });
}
- if (Context.getEventForwarder() != null) {
- Context.getEventForwarder().forwardEvent(event, position, usersToForward);
- }
+
+ forwardEvent(event, position);
}
- public void updateEvents(Map<Event, Position> events) {
- for (Entry<Event, Position> event : events.entrySet()) {
- updateEvent(event.getKey(), event.getValue());
+ private void forwardEvent(Event event, Position position) {
+ if (eventForwarder != null) {
+ EventData eventData = new EventData();
+ eventData.setEvent(event);
+ eventData.setPosition(position);
+ eventData.setDevice(cacheManager.getObject(Device.class, event.getDeviceId()));
+ if (event.getGeofenceId() != 0) {
+ eventData.setGeofence(cacheManager.getObject(Geofence.class, event.getGeofenceId()));
+ }
+ if (event.getMaintenanceId() != 0) {
+ eventData.setMaintenance(cacheManager.getObject(Maintenance.class, event.getMaintenanceId()));
+ }
+ eventForwarder.forward(eventData, (success, throwable) -> {
+ if (!success) {
+ LOGGER.warn("Event forwarding failed", throwable);
+ }
+ });
}
}
- public Set<Typed> getAllNotificationTypes() {
- Set<Typed> types = new HashSet<>();
- Field[] fields = Event.class.getDeclaredFields();
- for (Field field : fields) {
- if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("TYPE_")) {
- try {
- types.add(new Typed(field.get(null).toString()));
- } catch (IllegalArgumentException | IllegalAccessException error) {
- LOGGER.warn("Get event types error", error);
- }
+ public void updateEvents(Map<Event, Position> events) {
+ for (Entry<Event, Position> entry : events.entrySet()) {
+ Event event = entry.getKey();
+ Position position = entry.getValue();
+ try {
+ cacheManager.addDevice(event.getDeviceId());
+ updateEvent(event, position);
+ } catch (StorageException e) {
+ throw new RuntimeException(e);
+ } finally {
+ cacheManager.removeDevice(event.getDeviceId());
}
}
- return types;
}
}
diff --git a/src/main/java/org/traccar/database/OpenIdProvider.java b/src/main/java/org/traccar/database/OpenIdProvider.java
new file mode 100644
index 000000000..312be8890
--- /dev/null
+++ b/src/main/java/org/traccar/database/OpenIdProvider.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2023 Daniel Raper (me@danr.uk)
+ *
+ * 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.database;
+
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.api.resource.SessionResource;
+import org.traccar.api.security.LoginService;
+import org.traccar.model.User;
+import org.traccar.storage.StorageException;
+import org.traccar.helper.LogAction;
+import org.traccar.helper.WebHelper;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse.BodyHandlers;
+import java.security.GeneralSecurityException;
+import java.util.List;
+import java.util.Map;
+import java.io.IOException;
+import jakarta.servlet.http.HttpServletRequest;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+
+import com.nimbusds.oauth2.sdk.http.HTTPResponse;
+import com.nimbusds.oauth2.sdk.AuthorizationCode;
+import com.nimbusds.oauth2.sdk.ResponseType;
+import com.nimbusds.oauth2.sdk.Scope;
+import com.nimbusds.oauth2.sdk.AuthorizationGrant;
+import com.nimbusds.oauth2.sdk.TokenRequest;
+import com.nimbusds.oauth2.sdk.TokenResponse;
+import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.oauth2.sdk.AuthorizationResponse;
+import com.nimbusds.oauth2.sdk.auth.Secret;
+import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
+import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
+import com.nimbusds.oauth2.sdk.id.State;
+import com.nimbusds.oauth2.sdk.id.ClientID;
+import com.nimbusds.openid.connect.sdk.OIDCTokenResponse;
+import com.nimbusds.openid.connect.sdk.OIDCTokenResponseParser;
+import com.nimbusds.openid.connect.sdk.UserInfoResponse;
+import com.nimbusds.openid.connect.sdk.UserInfoRequest;
+import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+import com.nimbusds.openid.connect.sdk.claims.UserInfo;
+
+public class OpenIdProvider {
+ private final Boolean force;
+ private final ClientID clientId;
+ private final ClientAuthentication clientAuth;
+ private URI callbackUrl;
+ private URI authUrl;
+ private URI tokenUrl;
+ private URI userInfoUrl;
+ private URI baseUrl;
+ private final String adminGroup;
+ private final String allowGroup;
+
+ private LoginService loginService;
+
+ @Inject
+ public OpenIdProvider(
+ Config config, LoginService loginService, HttpClient httpClient, ObjectMapper objectMapper
+ ) throws InterruptedException, IOException, URISyntaxException {
+ this.loginService = loginService;
+
+ force = config.getBoolean(Keys.OPENID_FORCE);
+ clientId = new ClientID(config.getString(Keys.OPENID_CLIENT_ID));
+ clientAuth = new ClientSecretBasic(clientId, new Secret(config.getString(Keys.OPENID_CLIENT_SECRET)));
+
+ baseUrl = new URI(WebHelper.retrieveWebUrl(config));
+ callbackUrl = new URI(WebHelper.retrieveWebUrl(config) + "/api/session/openid/callback");
+
+ if (config.hasKey(Keys.OPENID_ISSUER_URL)) {
+ HttpRequest httpRequest = HttpRequest.newBuilder(
+ URI.create(config.getString(Keys.OPENID_ISSUER_URL) + "/.well-known/openid-configuration"))
+ .header("Accept", "application/json")
+ .build();
+
+ String httpResponse = httpClient.send(httpRequest, BodyHandlers.ofString()).body();
+
+ Map<String, Object> discoveryMap = objectMapper.readValue(
+ httpResponse, new TypeReference<Map<String, Object>>() { });
+
+ authUrl = new URI((String) discoveryMap.get("authorization_endpoint"));
+ tokenUrl = new URI((String) discoveryMap.get("token_endpoint"));
+ userInfoUrl = new URI((String) discoveryMap.get("userinfo_endpoint"));
+ } else {
+ authUrl = new URI(config.getString(Keys.OPENID_AUTH_URL));
+ tokenUrl = new URI(config.getString(Keys.OPENID_TOKEN_URL));
+ userInfoUrl = new URI(config.getString(Keys.OPENID_USERINFO_URL));
+ }
+
+ adminGroup = config.getString(Keys.OPENID_ADMIN_GROUP);
+ allowGroup = config.getString(Keys.OPENID_ALLOW_GROUP);
+ }
+
+ public URI createAuthUri() {
+ Scope scope = new Scope("openid", "profile", "email");
+
+ if (adminGroup != null) {
+ scope.add("groups");
+ }
+
+ AuthenticationRequest.Builder request = new AuthenticationRequest.Builder(
+ new ResponseType("code"),
+ scope,
+ clientId,
+ callbackUrl);
+
+ return request.endpointURI(authUrl)
+ .state(new State())
+ .build()
+ .toURI();
+ }
+
+ private OIDCTokenResponse getToken(
+ AuthorizationCode code) throws IOException, ParseException, GeneralSecurityException {
+ AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, callbackUrl);
+ TokenRequest tokenRequest = new TokenRequest(tokenUrl, clientAuth, codeGrant);
+
+ HTTPResponse tokenResponse = tokenRequest.toHTTPRequest().send();
+ TokenResponse token = OIDCTokenResponseParser.parse(tokenResponse);
+ if (!token.indicatesSuccess()) {
+ throw new GeneralSecurityException("Unable to authenticate with the OpenID Connect provider.");
+ }
+
+ return (OIDCTokenResponse) token.toSuccessResponse();
+ }
+
+ private UserInfo getUserInfo(BearerAccessToken token) throws IOException, ParseException, GeneralSecurityException {
+ HTTPResponse httpResponse = new UserInfoRequest(userInfoUrl, token)
+ .toHTTPRequest()
+ .send();
+
+ UserInfoResponse userInfoResponse = UserInfoResponse.parse(httpResponse);
+
+ if (!userInfoResponse.indicatesSuccess()) {
+ throw new GeneralSecurityException(
+ "Failed to access OpenID Connect user info endpoint. Please contact your administrator.");
+ }
+
+ return userInfoResponse.toSuccessResponse().getUserInfo();
+ }
+
+ public URI handleCallback(
+ URI requestUri, HttpServletRequest request
+ ) throws StorageException, ParseException, IOException, GeneralSecurityException {
+ AuthorizationResponse response = AuthorizationResponse.parse(requestUri);
+
+ if (!response.indicatesSuccess()) {
+ throw new GeneralSecurityException(response.toErrorResponse().getErrorObject().getDescription());
+ }
+
+ AuthorizationCode authCode = response.toSuccessResponse().getAuthorizationCode();
+
+ if (authCode == null) {
+ throw new GeneralSecurityException("Malformed OpenID callback.");
+ }
+
+ OIDCTokenResponse tokens = getToken(authCode);
+
+ BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken();
+
+ UserInfo userInfo = getUserInfo(bearerToken);
+
+ List<String> userGroups = userInfo.getStringListClaim("groups");
+ Boolean administrator = adminGroup != null && userGroups.contains(adminGroup);
+
+ if (!(administrator || allowGroup == null || userGroups.contains(allowGroup))) {
+ throw new GeneralSecurityException("Your OpenID Groups do not permit access to Traccar.");
+ }
+
+ User user = loginService.login(userInfo.getEmailAddress(), userInfo.getName(), administrator);
+
+ request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId());
+ LogAction.login(user.getId(), WebHelper.retrieveRemoteAddress(request));
+
+ return baseUrl;
+ }
+
+ public boolean getForce() {
+ return force;
+ }
+}
diff --git a/src/main/java/org/traccar/database/PermissionsManager.java b/src/main/java/org/traccar/database/PermissionsManager.java
deleted file mode 100644
index 2bb808033..000000000
--- a/src/main/java/org/traccar/database/PermissionsManager.java
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- * Copyright 2015 - 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.database;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.model.Attribute;
-import org.traccar.model.BaseModel;
-import org.traccar.model.Calendar;
-import org.traccar.model.Command;
-import org.traccar.model.Device;
-import org.traccar.model.Driver;
-import org.traccar.model.Geofence;
-import org.traccar.model.Group;
-import org.traccar.model.Maintenance;
-import org.traccar.model.ManagedUser;
-import org.traccar.model.Notification;
-import org.traccar.model.Order;
-import org.traccar.model.Permission;
-import org.traccar.model.Server;
-import org.traccar.model.User;
-import org.traccar.storage.StorageException;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-public class PermissionsManager {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(PermissionsManager.class);
-
- private final DataManager dataManager;
- private final UsersManager usersManager;
-
- private volatile Server server;
-
- private final ReadWriteLock lock = new ReentrantReadWriteLock();
-
- private final Map<Long, Set<Long>> groupPermissions = new HashMap<>();
- private final Map<Long, Set<Long>> devicePermissions = new HashMap<>();
- private final Map<Long, Set<Long>> deviceUsers = new HashMap<>();
- private final Map<Long, Set<Long>> groupDevices = new HashMap<>();
-
- public PermissionsManager(DataManager dataManager, UsersManager usersManager) {
- this.dataManager = dataManager;
- this.usersManager = usersManager;
- refreshServer();
- refreshDeviceAndGroupPermissions();
- }
-
- protected final void readLock() {
- lock.readLock().lock();
- }
-
- protected final void readUnlock() {
- lock.readLock().unlock();
- }
-
- protected final void writeLock() {
- lock.writeLock().lock();
- }
-
- protected final void writeUnlock() {
- lock.writeLock().unlock();
- }
-
- public User getUser(long userId) {
- readLock();
- try {
- return usersManager.getById(userId);
- } finally {
- readUnlock();
- }
- }
-
- public Set<Long> getGroupPermissions(long userId) {
- readLock();
- try {
- if (!groupPermissions.containsKey(userId)) {
- groupPermissions.put(userId, new HashSet<>());
- }
- return groupPermissions.get(userId);
- } finally {
- readUnlock();
- }
- }
-
- public Set<Long> getDevicePermissions(long userId) {
- readLock();
- try {
- if (!devicePermissions.containsKey(userId)) {
- devicePermissions.put(userId, new HashSet<>());
- }
- return devicePermissions.get(userId);
- } finally {
- readUnlock();
- }
- }
-
- private Set<Long> getAllDeviceUsers(long deviceId) {
- readLock();
- try {
- if (!deviceUsers.containsKey(deviceId)) {
- deviceUsers.put(deviceId, new HashSet<>());
- }
- return deviceUsers.get(deviceId);
- } finally {
- readUnlock();
- }
- }
-
- public Set<Long> getDeviceUsers(long deviceId) {
- Device device = Context.getIdentityManager().getById(deviceId);
- if (device != null && !device.getDisabled()) {
- return getAllDeviceUsers(deviceId);
- } else {
- Set<Long> result = new HashSet<>();
- for (long userId : getAllDeviceUsers(deviceId)) {
- if (getUserAdmin(userId)) {
- result.add(userId);
- }
- }
- return result;
- }
- }
-
- public Set<Long> getGroupDevices(long groupId) {
- readLock();
- try {
- if (!groupDevices.containsKey(groupId)) {
- groupDevices.put(groupId, new HashSet<>());
- }
- return groupDevices.get(groupId);
- } finally {
- readUnlock();
- }
- }
-
- public void refreshServer() {
- try {
- server = dataManager.getServer();
- } catch (StorageException error) {
- LOGGER.warn("Refresh server config error", error);
- }
- }
-
- public final void refreshDeviceAndGroupPermissions() {
- writeLock();
- try {
- groupPermissions.clear();
- devicePermissions.clear();
- try {
- GroupTree groupTree = new GroupTree(Context.getGroupsManager().getItems(
- Context.getGroupsManager().getAllItems()),
- Context.getDeviceManager().getAllDevices());
- for (Permission groupPermission : dataManager.getPermissions(User.class, Group.class)) {
- Set<Long> userGroupPermissions = getGroupPermissions(groupPermission.getOwnerId());
- Set<Long> userDevicePermissions = getDevicePermissions(groupPermission.getOwnerId());
- userGroupPermissions.add(groupPermission.getPropertyId());
- for (Group group : groupTree.getGroups(groupPermission.getPropertyId())) {
- userGroupPermissions.add(group.getId());
- }
- for (Device device : groupTree.getDevices(groupPermission.getPropertyId())) {
- userDevicePermissions.add(device.getId());
- }
- }
-
- for (Permission devicePermission : dataManager.getPermissions(User.class, Device.class)) {
- getDevicePermissions(devicePermission.getOwnerId()).add(devicePermission.getPropertyId());
- }
-
- groupDevices.clear();
- for (long groupId : Context.getGroupsManager().getAllItems()) {
- for (Device device : groupTree.getDevices(groupId)) {
- getGroupDevices(groupId).add(device.getId());
- }
- }
-
- } catch (StorageException | ClassNotFoundException error) {
- LOGGER.warn("Refresh device permissions error", error);
- }
-
- deviceUsers.clear();
- for (Map.Entry<Long, Set<Long>> entry : devicePermissions.entrySet()) {
- for (long deviceId : entry.getValue()) {
- getAllDeviceUsers(deviceId).add(entry.getKey());
- }
- }
- } finally {
- writeUnlock();
- }
- }
-
- public boolean getUserAdmin(long userId) {
- User user = getUser(userId);
- return user != null && user.getAdministrator();
- }
-
- public void checkAdmin(long userId) throws SecurityException {
- if (!getUserAdmin(userId)) {
- throw new SecurityException("Admin access required");
- }
- }
-
- public boolean getUserManager(long userId) {
- User user = getUser(userId);
- return user != null && user.getUserLimit() != 0;
- }
-
- public void checkManager(long userId) throws SecurityException {
- if (!getUserManager(userId)) {
- throw new SecurityException("Manager access required");
- }
- }
-
- public void checkManager(long userId, long managedUserId) throws SecurityException {
- checkManager(userId);
- if (!usersManager.getUserItems(userId).contains(managedUserId)) {
- throw new SecurityException("User access denied");
- }
- }
-
- public void checkUserLimit(long userId) throws SecurityException {
- int userLimit = getUser(userId).getUserLimit();
- if (userLimit != -1 && usersManager.getUserItems(userId).size() >= userLimit) {
- throw new SecurityException("Manager user limit reached");
- }
- }
-
- public void checkDeviceLimit(long userId) throws SecurityException {
- int deviceLimit = getUser(userId).getDeviceLimit();
- if (deviceLimit != -1) {
- int deviceCount;
- if (getUserManager(userId)) {
- deviceCount = Context.getDeviceManager().getAllManagedItems(userId).size();
- } else {
- deviceCount = Context.getDeviceManager().getAllUserItems(userId).size();
- }
- if (deviceCount >= deviceLimit) {
- throw new SecurityException("User device limit reached");
- }
- }
- }
-
- public boolean getUserReadonly(long userId) {
- User user = getUser(userId);
- return user != null && user.getReadonly();
- }
-
- public boolean getUserDeviceReadonly(long userId) {
- User user = getUser(userId);
- return user != null && user.getDeviceReadonly();
- }
-
- public boolean getUserLimitCommands(long userId) {
- User user = getUser(userId);
- return user != null && user.getLimitCommands();
- }
-
- public boolean getUserDisableReport(long userId) {
- User user = getUser(userId);
- return user != null && user.getDisableReports();
- }
-
- public void checkReadonly(long userId) throws SecurityException {
- if (!getUserAdmin(userId) && (server.getReadonly() || getUserReadonly(userId))) {
- throw new SecurityException("Account is readonly");
- }
- }
-
- public void checkDeviceReadonly(long userId) throws SecurityException {
- if (!getUserAdmin(userId) && (server.getDeviceReadonly() || getUserDeviceReadonly(userId))) {
- throw new SecurityException("Account is device readonly");
- }
- }
-
- public void checkLimitCommands(long userId) throws SecurityException {
- if (!getUserAdmin(userId) && (server.getLimitCommands() || getUserLimitCommands(userId))) {
- throw new SecurityException("Account has limit sending commands");
- }
- }
-
- public void checkDisableReports(long userId) throws SecurityException {
- if (!getUserAdmin(userId) && (server.getDisableReports() || getUserDisableReport(userId))) {
- throw new SecurityException("Account has reports disabled");
- }
- }
-
- public void checkUserDeviceCommand(long userId, long deviceId, long commandId) throws SecurityException {
- if (!getUserAdmin(userId) && Context.getCommandsManager().checkDeviceCommand(deviceId, commandId)) {
- throw new SecurityException("Command can not be sent to this device");
- }
- }
-
- public void checkUserEnabled(long userId) throws SecurityException {
- User user = getUser(userId);
- if (user == null) {
- throw new SecurityException("Unknown account");
- }
- if (user.getDisabled()) {
- throw new SecurityException("Account is disabled");
- }
- if (user.getExpirationTime() != null && System.currentTimeMillis() > user.getExpirationTime().getTime()) {
- throw new SecurityException("Account has expired");
- }
- }
-
- public void checkUserUpdate(long userId, User before, User after) throws SecurityException {
- if (before.getAdministrator() != after.getAdministrator()
- || before.getDeviceLimit() != after.getDeviceLimit()
- || before.getUserLimit() != after.getUserLimit()) {
- checkAdmin(userId);
- }
- User user = getUser(userId);
- if (user != null && user.getExpirationTime() != null
- && (after.getExpirationTime() == null
- || user.getExpirationTime().compareTo(after.getExpirationTime()) < 0)) {
- checkAdmin(userId);
- }
- if (before.getReadonly() != after.getReadonly()
- || before.getDeviceReadonly() != after.getDeviceReadonly()
- || before.getDisabled() != after.getDisabled()
- || before.getLimitCommands() != after.getLimitCommands()
- || before.getDisableReports() != after.getDisableReports()) {
- if (userId == after.getId()) {
- checkAdmin(userId);
- }
- if (!getUserAdmin(userId)) {
- checkManager(userId);
- }
- }
- }
-
- public void checkUser(long userId, long managedUserId) throws SecurityException {
- if (userId != managedUserId && !getUserAdmin(userId)) {
- checkManager(userId, managedUserId);
- }
- }
-
- public void checkGroup(long userId, long groupId) throws SecurityException {
- if (!getGroupPermissions(userId).contains(groupId) && !getUserAdmin(userId)) {
- checkManager(userId);
- for (long managedUserId : usersManager.getUserItems(userId)) {
- if (getGroupPermissions(managedUserId).contains(groupId)) {
- return;
- }
- }
- throw new SecurityException("Group access denied");
- }
- }
-
- public void checkDevice(long userId, long deviceId) throws SecurityException {
- if (!Context.getDeviceManager().getUserItems(userId).contains(deviceId) && !getUserAdmin(userId)) {
- checkManager(userId);
- for (long managedUserId : usersManager.getUserItems(userId)) {
- if (Context.getDeviceManager().getUserItems(managedUserId).contains(deviceId)) {
- return;
- }
- }
- throw new SecurityException("Device access denied");
- }
- }
-
- public void checkRegistration(long userId) {
- if (!server.getRegistration() && !getUserAdmin(userId)) {
- throw new SecurityException("Registration disabled");
- }
- }
-
- public void checkPermission(Class<?> object, long userId, long objectId)
- throws SecurityException {
- SimpleObjectManager<? extends BaseModel> manager = null;
-
- if (object.equals(Device.class)) {
- checkDevice(userId, objectId);
- } else if (object.equals(Group.class)) {
- checkGroup(userId, objectId);
- } else if (object.equals(User.class) || object.equals(ManagedUser.class)) {
- checkUser(userId, objectId);
- } else if (object.equals(Geofence.class)) {
- manager = Context.getGeofenceManager();
- } else if (object.equals(Attribute.class)) {
- manager = Context.getAttributesManager();
- } else if (object.equals(Driver.class)) {
- manager = Context.getDriversManager();
- } else if (object.equals(Calendar.class)) {
- manager = Context.getCalendarManager();
- } else if (object.equals(Command.class)) {
- manager = Context.getCommandsManager();
- } else if (object.equals(Maintenance.class)) {
- manager = Context.getMaintenancesManager();
- } else if (object.equals(Notification.class)) {
- manager = Context.getNotificationManager();
- } else if (object.equals(Order.class)) {
- manager = Context.getOrderManager();
- } else {
- throw new IllegalArgumentException("Unknown object type");
- }
-
- if (manager != null && !manager.checkItemPermission(userId, objectId) && !getUserAdmin(userId)) {
- checkManager(userId);
- for (long managedUserId : usersManager.getManagedItems(userId)) {
- if (manager.checkItemPermission(managedUserId, objectId)) {
- return;
- }
- }
- throw new SecurityException("Type " + object + " access denied");
- }
- }
-
- public void refreshAllUsersPermissions() {
- if (Context.getGeofenceManager() != null) {
- Context.getGeofenceManager().refreshUserItems();
- }
- Context.getCalendarManager().refreshUserItems();
- Context.getDriversManager().refreshUserItems();
- Context.getAttributesManager().refreshUserItems();
- Context.getCommandsManager().refreshUserItems();
- Context.getMaintenancesManager().refreshUserItems();
- if (Context.getNotificationManager() != null) {
- Context.getNotificationManager().refreshUserItems();
- }
- }
-
- public void refreshAllExtendedPermissions() {
- if (Context.getGeofenceManager() != null) {
- Context.getGeofenceManager().refreshExtendedPermissions();
- }
- Context.getDriversManager().refreshExtendedPermissions();
- Context.getAttributesManager().refreshExtendedPermissions();
- Context.getCommandsManager().refreshExtendedPermissions();
- Context.getMaintenancesManager().refreshExtendedPermissions();
- }
-
- public void refreshPermissions(Permission permission) {
- if (permission.getOwnerClass().equals(User.class)) {
- if (permission.getPropertyClass().equals(Device.class)
- || permission.getPropertyClass().equals(Group.class)) {
- refreshDeviceAndGroupPermissions();
- refreshAllExtendedPermissions();
- } else if (permission.getPropertyClass().equals(ManagedUser.class)) {
- usersManager.refreshUserItems();
- } else if (permission.getPropertyClass().equals(Geofence.class) && Context.getGeofenceManager() != null) {
- Context.getGeofenceManager().refreshUserItems();
- } else if (permission.getPropertyClass().equals(Driver.class)) {
- Context.getDriversManager().refreshUserItems();
- } else if (permission.getPropertyClass().equals(Attribute.class)) {
- Context.getAttributesManager().refreshUserItems();
- } else if (permission.getPropertyClass().equals(Calendar.class)) {
- Context.getCalendarManager().refreshUserItems();
- } else if (permission.getPropertyClass().equals(Command.class)) {
- Context.getCommandsManager().refreshUserItems();
- } else if (permission.getPropertyClass().equals(Maintenance.class)) {
- Context.getMaintenancesManager().refreshUserItems();
- } else if (permission.getPropertyClass().equals(Order.class)) {
- Context.getOrderManager().refreshUserItems();
- } else if (permission.getPropertyClass().equals(Notification.class)
- && Context.getNotificationManager() != null) {
- Context.getNotificationManager().refreshUserItems();
- }
- } else if (permission.getOwnerClass().equals(Device.class) || permission.getOwnerClass().equals(Group.class)) {
- if (permission.getPropertyClass().equals(Geofence.class) && Context.getGeofenceManager() != null) {
- Context.getGeofenceManager().refreshExtendedPermissions();
- } else if (permission.getPropertyClass().equals(Driver.class)) {
- Context.getDriversManager().refreshExtendedPermissions();
- } else if (permission.getPropertyClass().equals(Attribute.class)) {
- Context.getAttributesManager().refreshExtendedPermissions();
- } else if (permission.getPropertyClass().equals(Command.class)) {
- Context.getCommandsManager().refreshExtendedPermissions();
- } else if (permission.getPropertyClass().equals(Maintenance.class)) {
- Context.getMaintenancesManager().refreshExtendedPermissions();
- } else if (permission.getPropertyClass().equals(Order.class)) {
- Context.getOrderManager().refreshExtendedPermissions();
- } else if (permission.getPropertyClass().equals(Notification.class)
- && Context.getNotificationManager() != null) {
- Context.getNotificationManager().refreshExtendedPermissions();
- }
- }
- }
-
- public Server getServer() {
- return server;
- }
-
- public void updateServer(Server server) throws StorageException {
- dataManager.updateObject(server);
- this.server = server;
- }
-
- public User login(String email, String password) throws StorageException {
- User user = dataManager.login(email, password);
- if (user != null) {
- checkUserEnabled(user.getId());
- return getUser(user.getId());
- }
- return null;
- }
-
- public Object lookupAttribute(long userId, String key, Object defaultValue) {
- Object preference;
- Object serverPreference = server.getAttributes().get(key);
- Object userPreference = getUser(userId).getAttributes().get(key);
- if (server.getForceSettings()) {
- preference = serverPreference != null ? serverPreference : userPreference;
- } else {
- preference = userPreference != null ? userPreference : serverPreference;
- }
- return preference != null ? preference : defaultValue;
- }
-
-}
diff --git a/src/main/java/org/traccar/database/SimpleObjectManager.java b/src/main/java/org/traccar/database/SimpleObjectManager.java
deleted file mode 100644
index 78701720f..000000000
--- a/src/main/java/org/traccar/database/SimpleObjectManager.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.database;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.model.BaseModel;
-import org.traccar.model.Permission;
-import org.traccar.model.User;
-import org.traccar.storage.StorageException;
-
-public abstract class SimpleObjectManager<T extends BaseModel> extends BaseObjectManager<T>
- implements ManagableObjects {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(SimpleObjectManager.class);
-
- private Map<Long, Set<Long>> userItems;
-
- protected SimpleObjectManager(DataManager dataManager, Class<T> baseClass) {
- super(dataManager, baseClass);
- }
-
- @Override
- public final Set<Long> getUserItems(long userId) {
- try {
- readLock();
- Set<Long> result = userItems.get(userId);
- if (result != null) {
- return new HashSet<>(result);
- } else {
- return new HashSet<>();
- }
- } finally {
- readUnlock();
- }
- }
-
- @Override
- public Set<Long> getManagedItems(long userId) {
- Set<Long> result = getUserItems(userId);
- for (long managedUserId : Context.getUsersManager().getUserItems(userId)) {
- result.addAll(getUserItems(managedUserId));
- }
- return result;
- }
-
- public final boolean checkItemPermission(long userId, long itemId) {
- return getUserItems(userId).contains(itemId);
- }
-
- @Override
- public void refreshItems() {
- super.refreshItems();
- refreshUserItems();
- }
-
- public final void refreshUserItems() {
- if (getDataManager() != null) {
- try {
- writeLock();
- userItems = new ConcurrentHashMap<>();
- for (Permission permission : getDataManager().getPermissions(User.class, getBaseClass())) {
- Set<Long> items = userItems.computeIfAbsent(permission.getOwnerId(), key -> new HashSet<>());
- items.add(permission.getPropertyId());
- }
- } catch (StorageException | ClassNotFoundException error) {
- LOGGER.warn("Error getting permissions", error);
- } finally {
- writeUnlock();
- }
- }
- }
-
- @Override
- public void removeItem(long itemId) throws StorageException {
- super.removeItem(itemId);
- refreshUserItems();
- }
-
-}
diff --git a/src/main/java/org/traccar/database/StatisticsManager.java b/src/main/java/org/traccar/database/StatisticsManager.java
index 3579ce7a5..445e53e7c 100644
--- a/src/main/java/org/traccar/database/StatisticsManager.java
+++ b/src/main/java/org/traccar/database/StatisticsManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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.
@@ -19,16 +19,21 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.traccar.api.security.ServiceAccountUser;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.helper.DateUtil;
import org.traccar.model.Statistics;
+import org.traccar.storage.Storage;
import org.traccar.storage.StorageException;
-
-import javax.inject.Inject;
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.Form;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.Form;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
@@ -37,6 +42,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+@Singleton
public class StatisticsManager {
private static final Logger LOGGER = LoggerFactory.getLogger(StatisticsManager.class);
@@ -44,7 +50,7 @@ public class StatisticsManager {
private static final int SPLIT_MODE = Calendar.DAY_OF_MONTH;
private final Config config;
- private final DataManager dataManager;
+ private final Storage storage;
private final Client client;
private final ObjectMapper objectMapper;
@@ -52,6 +58,7 @@ public class StatisticsManager {
private final Set<Long> users = new HashSet<>();
private final Map<Long, String> deviceProtocols = new HashMap<>();
+ private final Map<Long, Integer> deviceMessages = new HashMap<>();
private int requests;
private int messagesReceived;
@@ -62,9 +69,9 @@ public class StatisticsManager {
private int geolocationRequests;
@Inject
- public StatisticsManager(Config config, DataManager dataManager, Client client, ObjectMapper objectMapper) {
+ public StatisticsManager(Config config, Storage storage, Client client, ObjectMapper objectMapper) {
this.config = config;
- this.dataManager = dataManager;
+ this.storage = storage;
this.client = client;
this.objectMapper = objectMapper;
}
@@ -93,8 +100,11 @@ public class StatisticsManager {
statistics.setProtocols(protocols);
}
+ statistics.set("modern", config.getString(Keys.WEB_PATH).contains("modern"));
+
users.clear();
deviceProtocols.clear();
+ deviceMessages.clear();
requests = 0;
messagesReceived = 0;
messagesStored = 0;
@@ -105,7 +115,7 @@ public class StatisticsManager {
}
try {
- dataManager.addObject(statistics);
+ storage.addObject(statistics, new Request(new Columns.Exclude("id")));
} catch (StorageException e) {
LOGGER.warn("Error saving statistics", e);
}
@@ -133,6 +143,13 @@ public class StatisticsManager {
LOGGER.warn("Failed to serialize protocols", e);
}
}
+ if (!statistics.getAttributes().isEmpty()) {
+ try {
+ form.param("attributes", objectMapper.writeValueAsString(statistics.getAttributes()));
+ } catch (JsonProcessingException e) {
+ LOGGER.warn("Failed to serialize attributes", e);
+ }
+ }
client.target(url).request().async().post(Entity.form(form));
}
@@ -142,7 +159,7 @@ public class StatisticsManager {
public synchronized void registerRequest(long userId) {
checkSplit();
requests += 1;
- if (userId != 0) {
+ if (userId != 0 && userId != ServiceAccountUser.ID) {
users.add(userId);
}
}
@@ -157,9 +174,14 @@ public class StatisticsManager {
messagesStored += 1;
if (deviceId != 0) {
deviceProtocols.put(deviceId, protocol);
+ deviceMessages.merge(deviceId, 1, Integer::sum);
}
}
+ public synchronized int messageStoredCount(long deviceId) {
+ return deviceMessages.getOrDefault(deviceId, 0);
+ }
+
public synchronized void registerMail() {
checkSplit();
mailSent += 1;
diff --git a/src/main/java/org/traccar/database/UsersManager.java b/src/main/java/org/traccar/database/UsersManager.java
deleted file mode 100644
index 31759dc8b..000000000
--- a/src/main/java/org/traccar/database/UsersManager.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.database;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.traccar.model.User;
-import org.traccar.storage.StorageException;
-
-public class UsersManager extends SimpleObjectManager<User> {
-
- private Map<String, User> usersTokens;
-
- public UsersManager(DataManager dataManager) {
- super(dataManager, User.class);
- if (usersTokens == null) {
- usersTokens = new ConcurrentHashMap<>();
- }
- }
-
- private void putToken(User user) {
- if (usersTokens == null) {
- usersTokens = new ConcurrentHashMap<>();
- }
- if (user.getToken() != null) {
- usersTokens.put(user.getToken(), user);
- }
- }
-
- @Override
- protected void addNewItem(User user) {
- super.addNewItem(user);
- putToken(user);
- }
-
- @Override
- protected void updateCachedItem(User user) {
- User cachedUser = getById(user.getId());
- super.updateCachedItem(user);
- putToken(user);
- if (cachedUser.getToken() != null && !cachedUser.getToken().equals(user.getToken())) {
- usersTokens.remove(cachedUser.getToken());
- }
- }
-
- @Override
- public void updateItem(User user) throws StorageException {
- if (user.getHashedPassword() != null) {
- getDataManager().updateUserPassword(user);
- }
- super.updateItem(user);
- }
-
- @Override
- protected void removeCachedItem(long userId) {
- User cachedUser = getById(userId);
- if (cachedUser != null) {
- String userToken = cachedUser.getToken();
- super.removeCachedItem(userId);
- if (userToken != null) {
- usersTokens.remove(userToken);
- }
- }
- }
-
- @Override
- public Set<Long> getManagedItems(long userId) {
- Set<Long> result = getUserItems(userId);
- result.add(userId);
- return result;
- }
-
- public User getUserByToken(String token) {
- return usersTokens.get(token);
- }
-
-}
diff --git a/src/main/java/org/traccar/forward/AmqpClient.java b/src/main/java/org/traccar/forward/AmqpClient.java
new file mode 100644
index 000000000..361cfffee
--- /dev/null
+++ b/src/main/java/org/traccar/forward/AmqpClient.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.forward;
+
+import com.rabbitmq.client.BuiltinExchangeType;
+import com.rabbitmq.client.Channel;
+import com.rabbitmq.client.Connection;
+import com.rabbitmq.client.ConnectionFactory;
+import com.rabbitmq.client.MessageProperties;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.util.concurrent.TimeoutException;
+
+public class AmqpClient {
+ private final Channel channel;
+ private final String exchange;
+ private final String topic;
+
+ AmqpClient(String connectionUrl, String exchange, String topic) {
+ this.exchange = exchange;
+ this.topic = topic;
+
+ ConnectionFactory factory = new ConnectionFactory();
+ try {
+ factory.setUri(connectionUrl);
+ } catch (NoSuchAlgorithmException | URISyntaxException | KeyManagementException e) {
+ throw new RuntimeException("Error while setting URI for RabbitMQ connection factory", e);
+ }
+
+ try {
+ Connection connection = factory.newConnection();
+ channel = connection.createChannel();
+ channel.exchangeDeclare(exchange, BuiltinExchangeType.TOPIC, true);
+ } catch (IOException | TimeoutException e) {
+ throw new RuntimeException("Error while creating and configuring RabbitMQ channel", e);
+ }
+ }
+
+ public void publishMessage(String message) throws IOException {
+ channel.basicPublish(exchange, topic, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
+ }
+}
diff --git a/src/main/java/org/traccar/forward/EventData.java b/src/main/java/org/traccar/forward/EventData.java
new file mode 100644
index 000000000..4471b10b3
--- /dev/null
+++ b/src/main/java/org/traccar/forward/EventData.java
@@ -0,0 +1,78 @@
+/*
+ * 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.forward;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+import org.traccar.model.Geofence;
+import org.traccar.model.Maintenance;
+import org.traccar.model.Position;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class EventData {
+
+ private Event event;
+
+ public Event getEvent() {
+ return event;
+ }
+
+ public void setEvent(Event event) {
+ this.event = event;
+ }
+
+ private Position position;
+
+ public Position getPosition() {
+ return position;
+ }
+
+ public void setPosition(Position position) {
+ this.position = position;
+ }
+
+ private Device device;
+
+ public Device getDevice() {
+ return device;
+ }
+
+ public void setDevice(Device device) {
+ this.device = device;
+ }
+
+ private Geofence geofence;
+
+ public Geofence getGeofence() {
+ return geofence;
+ }
+
+ public void setGeofence(Geofence geofence) {
+ this.geofence = geofence;
+ }
+
+ private Maintenance maintenance;
+
+ public Maintenance getMaintenance() {
+ return maintenance;
+ }
+
+ public void setMaintenance(Maintenance maintenance) {
+ this.maintenance = maintenance;
+ }
+
+}
diff --git a/src/main/java/org/traccar/database/ManagableObjects.java b/src/main/java/org/traccar/forward/EventForwarder.java
index ec9549493..1f991c0b5 100644
--- a/src/main/java/org/traccar/database/ManagableObjects.java
+++ b/src/main/java/org/traccar/forward/EventForwarder.java
@@ -1,6 +1,5 @@
/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ * 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.
@@ -14,14 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.database;
-
-import java.util.Set;
-
-public interface ManagableObjects {
-
- Set<Long> getUserItems(long userId);
-
- Set<Long> getManagedItems(long userId);
+package org.traccar.forward;
+public interface EventForwarder {
+ void forward(EventData eventData, ResultHandler resultHandler);
}
diff --git a/src/main/java/org/traccar/forward/EventForwarderAmqp.java b/src/main/java/org/traccar/forward/EventForwarderAmqp.java
new file mode 100644
index 000000000..5c38a4459
--- /dev/null
+++ b/src/main/java/org/traccar/forward/EventForwarderAmqp.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.forward;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import java.io.IOException;
+
+public class EventForwarderAmqp implements EventForwarder {
+
+ private final AmqpClient amqpClient;
+ private final ObjectMapper objectMapper;
+
+ public EventForwarderAmqp(Config config, ObjectMapper objectMapper) {
+ String connectionUrl = config.getString(Keys.EVENT_FORWARD_URL);
+ String exchange = config.getString(Keys.EVENT_FORWARD_EXCHANGE);
+ String topic = config.getString(Keys.EVENT_FORWARD_TOPIC);
+ this.objectMapper = objectMapper;
+ amqpClient = new AmqpClient(connectionUrl, exchange, topic);
+ }
+
+ @Override
+ public void forward(EventData eventData, ResultHandler resultHandler) {
+ try {
+ String value = objectMapper.writeValueAsString(eventData);
+ amqpClient.publishMessage(value);
+ resultHandler.onResult(true, null);
+ } catch (IOException e) {
+ resultHandler.onResult(false, e);
+ }
+ }
+}
diff --git a/src/main/java/org/traccar/forward/EventForwarderJson.java b/src/main/java/org/traccar/forward/EventForwarderJson.java
new file mode 100644
index 000000000..df53d3d46
--- /dev/null
+++ b/src/main/java/org/traccar/forward/EventForwarderJson.java
@@ -0,0 +1,68 @@
+/*
+ * 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.forward;
+
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.client.InvocationCallback;
+import jakarta.ws.rs.core.Response;
+
+public class EventForwarderJson implements EventForwarder {
+
+ private final String url;
+ private final String header;
+
+ private final Client client;
+
+ public EventForwarderJson(Config config, Client client) {
+ this.client = client;
+ url = config.getString(Keys.EVENT_FORWARD_URL);
+ header = config.getString(Keys.EVENT_FORWARD_HEADERS);
+ }
+
+ @Override
+ public void forward(EventData eventData, ResultHandler resultHandler) {
+ var requestBuilder = client.target(url).request();
+
+ if (header != null && !header.isEmpty()) {
+ for (String line: header.split("\\r?\\n")) {
+ String[] values = line.split(":", 2);
+ requestBuilder.header(values[0].trim(), values[1].trim());
+ }
+ }
+
+ requestBuilder.async().post(Entity.json(eventData), new InvocationCallback<Response>() {
+ @Override
+ public void completed(Response response) {
+ if (response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL) {
+ resultHandler.onResult(true, null);
+ } else {
+ int code = response.getStatusInfo().getStatusCode();
+ resultHandler.onResult(false, new RuntimeException("HTTP code " + code));
+ }
+ }
+
+ @Override
+ public void failed(Throwable throwable) {
+ resultHandler.onResult(false, throwable);
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/forward/EventForwarderKafka.java b/src/main/java/org/traccar/forward/EventForwarderKafka.java
new file mode 100644
index 000000000..e65c3a51b
--- /dev/null
+++ b/src/main/java/org/traccar/forward/EventForwarderKafka.java
@@ -0,0 +1,58 @@
+/*
+ * 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.forward;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.kafka.clients.producer.KafkaProducer;
+import org.apache.kafka.clients.producer.Producer;
+import org.apache.kafka.clients.producer.ProducerRecord;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import java.util.Properties;
+
+public class EventForwarderKafka implements EventForwarder {
+
+ private final Producer<String, String> producer;
+ private final ObjectMapper objectMapper;
+
+ private final String topic;
+
+ public EventForwarderKafka(Config config, ObjectMapper objectMapper) {
+ this.objectMapper = objectMapper;
+ Properties properties = new Properties();
+ properties.put("bootstrap.servers", config.getString(Keys.EVENT_FORWARD_URL));
+ properties.put("acks", "all");
+ properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
+ properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
+ producer = new KafkaProducer<>(properties);
+ topic = config.getString(Keys.EVENT_FORWARD_TOPIC);
+ }
+
+ @Override
+ public void forward(EventData eventData, ResultHandler resultHandler) {
+ try {
+ String key = Long.toString(eventData.getDevice().getId());
+ String value = objectMapper.writeValueAsString(eventData);
+ producer.send(new ProducerRecord<>(topic, key, value));
+ resultHandler.onResult(true, null);
+ } catch (JsonProcessingException e) {
+ resultHandler.onResult(false, e);
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/forward/EventForwarderMqtt.java b/src/main/java/org/traccar/forward/EventForwarderMqtt.java
new file mode 100644
index 000000000..7f4e29384
--- /dev/null
+++ b/src/main/java/org/traccar/forward/EventForwarderMqtt.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2022 - 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.forward;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.hivemq.client.mqtt.datatypes.MqttQos;
+import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient;
+import com.hivemq.client.mqtt.mqtt5.Mqtt5Client;
+import com.hivemq.client.mqtt.mqtt5.message.auth.Mqtt5SimpleAuth;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.UUID;
+
+public class EventForwarderMqtt implements EventForwarder {
+
+ private final Mqtt5AsyncClient client;
+ private final ObjectMapper objectMapper;
+
+ private final String topic;
+
+ public EventForwarderMqtt(Config config, ObjectMapper objectMapper) {
+ URI url;
+ try {
+ url = new URI(config.getString(Keys.EVENT_FORWARD_URL));
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+
+ String userInfo = url.getUserInfo();
+ Mqtt5SimpleAuth simpleAuth = null;
+ if (userInfo != null) {
+ int delimiter = userInfo.indexOf(':');
+ if (delimiter == -1) {
+ throw new IllegalArgumentException("Wrong credentials. Should be in format \"username:password\"");
+ } else {
+ simpleAuth = Mqtt5SimpleAuth.builder()
+ .username(userInfo.substring(0, delimiter++))
+ .password(userInfo.substring(delimiter).getBytes())
+ .build();
+ }
+ }
+
+ String host = url.getHost();
+ int port = url.getPort();
+ client = Mqtt5Client.builder()
+ .identifier("traccar-" + UUID.randomUUID())
+ .serverHost(host)
+ .serverPort(port)
+ .simpleAuth(simpleAuth)
+ .automaticReconnectWithDefaultConfig()
+ .buildAsync();
+
+ client.connectWith()
+ .send()
+ .whenComplete((message, e) -> {
+ if (e != null) {
+ throw new RuntimeException(e);
+ }
+ });
+
+ this.objectMapper = objectMapper;
+ topic = config.getString(Keys.EVENT_FORWARD_TOPIC);
+ }
+
+ @Override
+ public void forward(EventData eventData, ResultHandler resultHandler) {
+ byte[] payload;
+ try {
+ payload = objectMapper.writeValueAsString(eventData).getBytes();
+ } catch (JsonProcessingException e) {
+ resultHandler.onResult(false, e);
+ return;
+ }
+
+ client.publishWith()
+ .topic(topic)
+ .qos(MqttQos.AT_LEAST_ONCE)
+ .payload(payload)
+ .send()
+ .whenComplete((message, e) -> resultHandler.onResult(e == null, e));
+ }
+
+}
diff --git a/src/main/java/org/traccar/forward/NetworkForwarder.java b/src/main/java/org/traccar/forward/NetworkForwarder.java
new file mode 100644
index 000000000..86c9a77f3
--- /dev/null
+++ b/src/main/java/org/traccar/forward/NetworkForwarder.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.forward;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.HashMap;
+import java.util.Map;
+
+@Singleton
+public class NetworkForwarder {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(NetworkForwarder.class);
+
+ private final InetAddress destination;
+ private final DatagramSocket connectionUdp;
+ private final Map<InetSocketAddress, Socket> connectionsTcp = new HashMap<>();
+
+ @Inject
+ public NetworkForwarder(Config config) throws IOException {
+ destination = InetAddress.getByName(config.getString(Keys.SERVER_FORWARD));
+ connectionUdp = new DatagramSocket();
+ }
+
+ public void forward(InetSocketAddress source, int port, boolean datagram, byte[] data) {
+ try {
+ if (datagram) {
+ connectionUdp.send(new DatagramPacket(data, data.length, destination, port));
+ } else {
+ Socket connectionTcp = connectionsTcp.get(source);
+ if (connectionTcp == null || connectionTcp.isClosed()) {
+ connectionTcp = new Socket(destination, port);
+ connectionsTcp.put(source, connectionTcp);
+ }
+ connectionTcp.getOutputStream().write(data);
+ }
+ } catch (IOException e) {
+ LOGGER.warn("Network forwarding error", e);
+ }
+ }
+
+ public void disconnect(InetSocketAddress source) {
+ Socket connectionTcp = connectionsTcp.remove(source);
+ if (connectionTcp != null) {
+ try {
+ connectionTcp.close();
+ } catch (IOException e) {
+ LOGGER.warn("Connection close error", e);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/forward/PositionData.java b/src/main/java/org/traccar/forward/PositionData.java
new file mode 100644
index 000000000..784cf52f5
--- /dev/null
+++ b/src/main/java/org/traccar/forward/PositionData.java
@@ -0,0 +1,45 @@
+/*
+ * 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.forward;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.traccar.model.Device;
+import org.traccar.model.Position;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class PositionData {
+
+ private Position position;
+
+ public Position getPosition() {
+ return position;
+ }
+
+ public void setPosition(Position position) {
+ this.position = position;
+ }
+
+ private Device device;
+
+ public Device getDevice() {
+ return device;
+ }
+
+ public void setDevice(Device device) {
+ this.device = device;
+ }
+
+}
diff --git a/src/main/java/org/traccar/forward/PositionForwarder.java b/src/main/java/org/traccar/forward/PositionForwarder.java
new file mode 100644
index 000000000..58bd1dcc7
--- /dev/null
+++ b/src/main/java/org/traccar/forward/PositionForwarder.java
@@ -0,0 +1,20 @@
+/*
+ * 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.forward;
+
+public interface PositionForwarder {
+ void forward(PositionData positionData, ResultHandler resultHandler);
+}
diff --git a/src/main/java/org/traccar/forward/PositionForwarderAmqp.java b/src/main/java/org/traccar/forward/PositionForwarderAmqp.java
new file mode 100644
index 000000000..3996bda15
--- /dev/null
+++ b/src/main/java/org/traccar/forward/PositionForwarderAmqp.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.forward;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import java.io.IOException;
+
+public class PositionForwarderAmqp implements PositionForwarder {
+
+ private final AmqpClient amqpClient;
+ private final ObjectMapper objectMapper;
+
+ public PositionForwarderAmqp(Config config, ObjectMapper objectMapper) {
+ String connectionUrl = config.getString(Keys.FORWARD_URL);
+ String exchange = config.getString(Keys.FORWARD_EXCHANGE);
+ String topic = config.getString(Keys.FORWARD_TOPIC);
+ amqpClient = new AmqpClient(connectionUrl, exchange, topic);
+ this.objectMapper = objectMapper;
+ }
+
+ @Override
+ public void forward(PositionData positionData, ResultHandler resultHandler) {
+ try {
+ String value = objectMapper.writeValueAsString(positionData);
+ amqpClient.publishMessage(value);
+ resultHandler.onResult(true, null);
+ } catch (IOException e) {
+ resultHandler.onResult(false, e);
+ }
+ }
+}
diff --git a/src/main/java/org/traccar/forward/PositionForwarderJson.java b/src/main/java/org/traccar/forward/PositionForwarderJson.java
new file mode 100644
index 000000000..a0ad8ffd0
--- /dev/null
+++ b/src/main/java/org/traccar/forward/PositionForwarderJson.java
@@ -0,0 +1,86 @@
+/*
+ * 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.forward;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.client.InvocationCallback;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+
+public class PositionForwarderJson implements PositionForwarder {
+
+ private final String url;
+ private final String header;
+
+ private final Client client;
+ private final ObjectMapper objectMapper;
+
+ public PositionForwarderJson(Config config, Client client, ObjectMapper objectMapper) {
+ this.client = client;
+ this.objectMapper = objectMapper;
+ this.url = config.getString(Keys.FORWARD_URL);
+ this.header = config.getString(Keys.FORWARD_HEADER);
+ }
+
+ @Override
+ public void forward(PositionData positionData, ResultHandler resultHandler) {
+ var requestBuilder = client.target(url).request();
+
+ MediaType mediaType = MediaType.APPLICATION_JSON_TYPE;
+ if (header != null && !header.isEmpty()) {
+ for (String line: header.split("\\r?\\n")) {
+ String[] values = line.split(":", 2);
+ String headerName = values[0].trim();
+ String headerValue = values[1].trim();
+ if (headerName.equals(HttpHeaders.CONTENT_TYPE)) {
+ mediaType = MediaType.valueOf(headerValue);
+ } else {
+ requestBuilder.header(headerName, headerValue);
+ }
+ }
+ }
+
+ try {
+ var entity = Entity.entity(objectMapper.writeValueAsString(positionData), mediaType);
+ requestBuilder.async().post(entity, new InvocationCallback<Response>() {
+ @Override
+ public void completed(Response response) {
+ if (response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL) {
+ resultHandler.onResult(true, null);
+ } else {
+ int code = response.getStatusInfo().getStatusCode();
+ resultHandler.onResult(false, new RuntimeException("HTTP code " + code));
+ }
+ }
+
+ @Override
+ public void failed(Throwable throwable) {
+ resultHandler.onResult(false, throwable);
+ }
+ });
+ } catch (JsonProcessingException e) {
+ resultHandler.onResult(false, e);
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/forward/PositionForwarderKafka.java b/src/main/java/org/traccar/forward/PositionForwarderKafka.java
new file mode 100644
index 000000000..7432e9364
--- /dev/null
+++ b/src/main/java/org/traccar/forward/PositionForwarderKafka.java
@@ -0,0 +1,58 @@
+/*
+ * 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.forward;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.kafka.clients.producer.KafkaProducer;
+import org.apache.kafka.clients.producer.Producer;
+import org.apache.kafka.clients.producer.ProducerRecord;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import java.util.Properties;
+
+public class PositionForwarderKafka implements PositionForwarder {
+
+ private final Producer<String, String> producer;
+ private final ObjectMapper objectMapper;
+
+ private final String topic;
+
+ public PositionForwarderKafka(Config config, ObjectMapper objectMapper) {
+ this.objectMapper = objectMapper;
+ Properties properties = new Properties();
+ properties.put("bootstrap.servers", config.getString(Keys.FORWARD_URL));
+ properties.put("acks", "all");
+ properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
+ properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
+ producer = new KafkaProducer<>(properties);
+ topic = config.getString(Keys.FORWARD_TOPIC);
+ }
+
+ @Override
+ public void forward(PositionData positionData, ResultHandler resultHandler) {
+ try {
+ String key = Long.toString(positionData.getDevice().getId());
+ String value = objectMapper.writeValueAsString(positionData);
+ producer.send(new ProducerRecord<>(topic, key, value));
+ resultHandler.onResult(true, null);
+ } catch (JsonProcessingException e) {
+ resultHandler.onResult(false, e);
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/forward/PositionForwarderRedis.java b/src/main/java/org/traccar/forward/PositionForwarderRedis.java
new file mode 100644
index 000000000..539d247b6
--- /dev/null
+++ b/src/main/java/org/traccar/forward/PositionForwarderRedis.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.forward;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import redis.clients.jedis.Jedis;
+
+public class PositionForwarderRedis implements PositionForwarder {
+
+ private final String url;
+
+ private final ObjectMapper objectMapper;
+
+ public PositionForwarderRedis(Config config, ObjectMapper objectMapper) {
+ this.objectMapper = objectMapper;
+ this.url = config.getString(Keys.FORWARD_URL);
+ }
+
+ @Override
+ public void forward(PositionData positionData, ResultHandler resultHandler) {
+
+ try {
+ String key = "positions." + positionData.getDevice().getUniqueId();
+ String value = objectMapper.writeValueAsString(positionData.getPosition());
+ try (Jedis jedis = new Jedis(url)) {
+ jedis.lpush(key, value);
+ }
+ resultHandler.onResult(true, null);
+ } catch (JsonProcessingException e) {
+ resultHandler.onResult(false, e);
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/forward/PositionForwarderUrl.java b/src/main/java/org/traccar/forward/PositionForwarderUrl.java
new file mode 100644
index 000000000..33474d40b
--- /dev/null
+++ b/src/main/java/org/traccar/forward/PositionForwarderUrl.java
@@ -0,0 +1,166 @@
+/*
+ * 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.forward;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.helper.Checksum;
+import org.traccar.model.Device;
+import org.traccar.model.Position;
+
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.InvocationCallback;
+import jakarta.ws.rs.core.Response;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Calendar;
+import java.util.Formatter;
+import java.util.Locale;
+import java.util.TimeZone;
+
+public class PositionForwarderUrl implements PositionForwarder {
+
+ private final String url;
+ private final String header;
+
+ private final Client client;
+ private final ObjectMapper objectMapper;
+
+ public PositionForwarderUrl(Config config, Client client, ObjectMapper objectMapper) {
+ this.client = client;
+ this.objectMapper = objectMapper;
+ this.url = config.getString(Keys.FORWARD_URL);
+ this.header = config.getString(Keys.FORWARD_HEADER);
+ }
+
+ @Override
+ public void forward(PositionData positionData, ResultHandler resultHandler) {
+ try {
+ String url = formatRequest(positionData);
+ var requestBuilder = client.target(url).request();
+
+ if (header != null && !header.isEmpty()) {
+ for (String line: header.split("\\r?\\n")) {
+ String[] values = line.split(":", 2);
+ String headerName = values[0].trim();
+ String headerValue = values[1].trim();
+ requestBuilder.header(headerName, headerValue);
+ }
+ }
+
+ requestBuilder.async().get(new InvocationCallback<Response>() {
+ @Override
+ public void completed(Response response) {
+ if (response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL) {
+ resultHandler.onResult(true, null);
+ } else {
+ int code = response.getStatusInfo().getStatusCode();
+ resultHandler.onResult(false, new RuntimeException("HTTP code " + code));
+ }
+ }
+
+ @Override
+ public void failed(Throwable throwable) {
+ resultHandler.onResult(false, throwable);
+ }
+ });
+ } catch (UnsupportedEncodingException | JsonProcessingException e) {
+ resultHandler.onResult(false, e);
+ }
+ }
+
+ public String formatRequest(
+ PositionData positionData) throws UnsupportedEncodingException, JsonProcessingException {
+
+ Position position = positionData.getPosition();
+ Device device = positionData.getDevice();
+
+ String request = url
+ .replace("{name}", URLEncoder.encode(device.getName(), StandardCharsets.UTF_8))
+ .replace("{uniqueId}", device.getUniqueId())
+ .replace("{status}", device.getStatus())
+ .replace("{deviceId}", String.valueOf(position.getDeviceId()))
+ .replace("{protocol}", String.valueOf(position.getProtocol()))
+ .replace("{deviceTime}", String.valueOf(position.getDeviceTime().getTime()))
+ .replace("{fixTime}", String.valueOf(position.getFixTime().getTime()))
+ .replace("{valid}", String.valueOf(position.getValid()))
+ .replace("{latitude}", String.valueOf(position.getLatitude()))
+ .replace("{longitude}", String.valueOf(position.getLongitude()))
+ .replace("{altitude}", String.valueOf(position.getAltitude()))
+ .replace("{speed}", String.valueOf(position.getSpeed()))
+ .replace("{course}", String.valueOf(position.getCourse()))
+ .replace("{accuracy}", String.valueOf(position.getAccuracy()))
+ .replace("{statusCode}", calculateStatus(position));
+
+ if (position.getAddress() != null) {
+ request = request.replace(
+ "{address}", URLEncoder.encode(position.getAddress(), StandardCharsets.UTF_8));
+ }
+
+ if (request.contains("{attributes}")) {
+ String attributes = objectMapper.writeValueAsString(position.getAttributes());
+ request = request.replace(
+ "{attributes}", URLEncoder.encode(attributes, StandardCharsets.UTF_8));
+ }
+
+ if (request.contains("{gprmc}")) {
+ request = request.replace("{gprmc}", formatSentence(position));
+ }
+
+ return request;
+ }
+
+ private static String formatSentence(Position position) {
+
+ StringBuilder s = new StringBuilder("$GPRMC,");
+
+ try (Formatter f = new Formatter(s, Locale.ENGLISH)) {
+
+ Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.ENGLISH);
+ calendar.setTimeInMillis(position.getFixTime().getTime());
+
+ f.format("%1$tH%1$tM%1$tS.%1$tL,A,", calendar);
+
+ double lat = position.getLatitude();
+ double lon = position.getLongitude();
+
+ f.format("%02d%07.4f,%c,", (int) Math.abs(lat), Math.abs(lat) % 1 * 60, lat < 0 ? 'S' : 'N');
+ f.format("%03d%07.4f,%c,", (int) Math.abs(lon), Math.abs(lon) % 1 * 60, lon < 0 ? 'W' : 'E');
+
+ f.format("%.2f,%.2f,", position.getSpeed(), position.getCourse());
+ f.format("%1$td%1$tm%1$ty,,", calendar);
+ }
+
+ s.append(Checksum.nmea(s.substring(1)));
+
+ return s.toString();
+ }
+
+ // OpenGTS status code
+ private String calculateStatus(Position position) {
+ if (position.hasAttribute(Position.KEY_ALARM)) {
+ return "0xF841"; // STATUS_PANIC_ON
+ } else if (position.getSpeed() < 1.0) {
+ return "0xF020"; // STATUS_LOCATION
+ } else {
+ return "0xF11C"; // STATUS_MOTION_MOVING
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/forward/ResultHandler.java b/src/main/java/org/traccar/forward/ResultHandler.java
new file mode 100644
index 000000000..009daf495
--- /dev/null
+++ b/src/main/java/org/traccar/forward/ResultHandler.java
@@ -0,0 +1,20 @@
+/*
+ * 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.forward;
+
+public interface ResultHandler {
+ void onResult(boolean success, Throwable throwable);
+}
diff --git a/src/main/java/org/traccar/geocoder/BanGeocoder.java b/src/main/java/org/traccar/geocoder/BanGeocoder.java
index b1f0900a4..e2ff72311 100644
--- a/src/main/java/org/traccar/geocoder/BanGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/BanGeocoder.java
@@ -20,13 +20,14 @@ package org.traccar.geocoder;
* API documentation: https://adresse.data.gouv.fr/api
*/
-import javax.json.JsonArray;
-import javax.json.JsonObject;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class BanGeocoder extends JsonGeocoder {
- public BanGeocoder(int cacheSize, AddressFormat addressFormat) {
- super("https://api-adresse.data.gouv.fr/reverse/?lat=%f&lon=%f", cacheSize, addressFormat);
+ public BanGeocoder(Client client, int cacheSize, AddressFormat addressFormat) {
+ super(client, "https://api-adresse.data.gouv.fr/reverse/?lat=%f&lon=%f", cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java b/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java
index 32a26ee0c..bc3b15ce7 100644
--- a/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java
@@ -16,13 +16,14 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class BingMapsGeocoder extends JsonGeocoder {
- public BingMapsGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) {
- super(url + "/Locations/%f,%f?key=" + key + "&include=ciso2", cacheSize, addressFormat);
+ public BingMapsGeocoder(Client client, String url, String key, int cacheSize, AddressFormat addressFormat) {
+ super(client, url + "/Locations/%f,%f?key=" + key + "&include=ciso2", cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/FactualGeocoder.java b/src/main/java/org/traccar/geocoder/FactualGeocoder.java
index f540eb8fe..6c8891316 100644
--- a/src/main/java/org/traccar/geocoder/FactualGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/FactualGeocoder.java
@@ -16,7 +16,8 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonObject;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class FactualGeocoder extends JsonGeocoder {
@@ -28,8 +29,8 @@ public class FactualGeocoder extends JsonGeocoder {
return url;
}
- public FactualGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) {
- super(formatUrl(url, key), cacheSize, addressFormat);
+ public FactualGeocoder(Client client, String url, String key, int cacheSize, AddressFormat addressFormat) {
+ super(client, formatUrl(url, key), cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/GeoapifyGeocoder.java b/src/main/java/org/traccar/geocoder/GeoapifyGeocoder.java
index ef0e4c8bd..35a47bb88 100644
--- a/src/main/java/org/traccar/geocoder/GeoapifyGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/GeoapifyGeocoder.java
@@ -15,8 +15,9 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class GeoapifyGeocoder extends JsonGeocoder {
@@ -31,8 +32,8 @@ public class GeoapifyGeocoder extends JsonGeocoder {
return url;
}
- public GeoapifyGeocoder(String key, String language, int cacheSize, AddressFormat addressFormat) {
- super(formatUrl(key, language), cacheSize, addressFormat);
+ public GeoapifyGeocoder(Client client, String key, String language, int cacheSize, AddressFormat addressFormat) {
+ super(client, formatUrl(key, language), cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java b/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java
index 39a3300a0..80b00b3cc 100644
--- a/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java
@@ -15,7 +15,8 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonObject;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class GeocodeFarmGeocoder extends JsonGeocoder {
@@ -30,8 +31,9 @@ public class GeocodeFarmGeocoder extends JsonGeocoder {
}
return url;
}
- public GeocodeFarmGeocoder(String key, String language, int cacheSize, AddressFormat addressFormat) {
- super(formatUrl(key, language), cacheSize, addressFormat);
+ public GeocodeFarmGeocoder(
+ Client client, String key, String language, int cacheSize, AddressFormat addressFormat) {
+ super(client, formatUrl(key, language), cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java b/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java
index aca360c3d..e88962e1a 100644
--- a/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java
@@ -15,7 +15,8 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonObject;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class GeocodeXyzGeocoder extends JsonGeocoder {
@@ -27,8 +28,8 @@ public class GeocodeXyzGeocoder extends JsonGeocoder {
return url;
}
- public GeocodeXyzGeocoder(String key, int cacheSize, AddressFormat addressFormat) {
- super(formatUrl(key), cacheSize, addressFormat);
+ public GeocodeXyzGeocoder(Client client, String key, int cacheSize, AddressFormat addressFormat) {
+ super(client, formatUrl(key), cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/Geocoder.java b/src/main/java/org/traccar/geocoder/Geocoder.java
index 587a27520..f4abe871a 100644
--- a/src/main/java/org/traccar/geocoder/Geocoder.java
+++ b/src/main/java/org/traccar/geocoder/Geocoder.java
@@ -15,6 +15,8 @@
*/
package org.traccar.geocoder;
+import org.traccar.database.StatisticsManager;
+
public interface Geocoder {
interface ReverseGeocoderCallback {
@@ -27,4 +29,6 @@ public interface Geocoder {
String getAddress(double latitude, double longitude, ReverseGeocoderCallback callback);
+ void setStatisticsManager(StatisticsManager statisticsManager);
+
}
diff --git a/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java b/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java
index b4881a006..062e795eb 100644
--- a/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java
@@ -15,7 +15,8 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonObject;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class GisgraphyGeocoder extends JsonGeocoder {
@@ -27,8 +28,8 @@ public class GisgraphyGeocoder extends JsonGeocoder {
return url;
}
- public GisgraphyGeocoder(String url, int cacheSize, AddressFormat addressFormat) {
- super(formatUrl(url), cacheSize, addressFormat);
+ public GisgraphyGeocoder(Client client, String url, int cacheSize, AddressFormat addressFormat) {
+ super(client, formatUrl(url), cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/GoogleGeocoder.java b/src/main/java/org/traccar/geocoder/GoogleGeocoder.java
index 9494cab45..93f128b46 100644
--- a/src/main/java/org/traccar/geocoder/GoogleGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/GoogleGeocoder.java
@@ -15,9 +15,10 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
-import javax.json.JsonString;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonString;
+import jakarta.ws.rs.client.Client;
public class GoogleGeocoder extends JsonGeocoder {
@@ -32,8 +33,8 @@ public class GoogleGeocoder extends JsonGeocoder {
return url;
}
- public GoogleGeocoder(String key, String language, int cacheSize, AddressFormat addressFormat) {
- super(formatUrl(key, language), cacheSize, addressFormat);
+ public GoogleGeocoder(Client client, String key, String language, int cacheSize, AddressFormat addressFormat) {
+ super(client, formatUrl(key, language), cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/HereGeocoder.java b/src/main/java/org/traccar/geocoder/HereGeocoder.java
index 40390e65b..2d1bc1bf4 100644
--- a/src/main/java/org/traccar/geocoder/HereGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/HereGeocoder.java
@@ -15,7 +15,8 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonObject;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class HereGeocoder extends JsonGeocoder {
@@ -35,8 +36,9 @@ public class HereGeocoder extends JsonGeocoder {
}
public HereGeocoder(
- String url, String id, String key, String language, int cacheSize, AddressFormat addressFormat) {
- super(formatUrl(url, id, key, language), cacheSize, addressFormat);
+ Client client, String url, String id, String key, String language,
+ int cacheSize, AddressFormat addressFormat) {
+ super(client, formatUrl(url, id, key, language), cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/JsonGeocoder.java b/src/main/java/org/traccar/geocoder/JsonGeocoder.java
index f20aa79d6..f9b039f43 100644
--- a/src/main/java/org/traccar/geocoder/JsonGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/JsonGeocoder.java
@@ -17,14 +17,12 @@ package org.traccar.geocoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.Main;
import org.traccar.database.StatisticsManager;
-import javax.json.JsonObject;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.client.Invocation;
-import javax.ws.rs.client.InvocationCallback;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.InvocationCallback;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -34,16 +32,19 @@ public abstract class JsonGeocoder implements Geocoder {
private static final Logger LOGGER = LoggerFactory.getLogger(JsonGeocoder.class);
+ private final Client client;
private final String url;
private final AddressFormat addressFormat;
+ private StatisticsManager statisticsManager;
private Map<Map.Entry<Double, Double>, String> cache;
- public JsonGeocoder(String url, final int cacheSize, AddressFormat addressFormat) {
+ public JsonGeocoder(Client client, String url, final int cacheSize, AddressFormat addressFormat) {
+ this.client = client;
this.url = url;
this.addressFormat = addressFormat;
if (cacheSize > 0) {
- this.cache = Collections.synchronizedMap(new LinkedHashMap<Map.Entry<Double, Double>, String>() {
+ this.cache = Collections.synchronizedMap(new LinkedHashMap<>() {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > cacheSize;
@@ -52,6 +53,11 @@ public abstract class JsonGeocoder implements Geocoder {
}
}
+ @Override
+ public void setStatisticsManager(StatisticsManager statisticsManager) {
+ this.statisticsManager = statisticsManager;
+ }
+
protected String readValue(JsonObject object, String key) {
if (object.containsKey(key) && !object.isNull(key)) {
return object.getString(key);
@@ -97,11 +103,11 @@ public abstract class JsonGeocoder implements Geocoder {
}
}
- if (Main.getInjector() != null) {
- Main.getInjector().getInstance(StatisticsManager.class).registerGeocoderRequest();
+ if (statisticsManager != null) {
+ statisticsManager.registerGeocoderRequest();
}
- Invocation.Builder request = Context.getClient().target(String.format(url, latitude, longitude)).request();
+ var request = client.target(String.format(url, latitude, longitude)).request();
if (callback != null) {
request.async().get(new InvocationCallback<JsonObject>() {
diff --git a/src/main/java/org/traccar/DeviceSession.java b/src/main/java/org/traccar/geocoder/LocationIqGeocoder.java
index 322381807..f304ffeff 100644
--- a/src/main/java/org/traccar/DeviceSession.java
+++ b/src/main/java/org/traccar/geocoder/LocationIqGeocoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * 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.
@@ -13,30 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar;
+package org.traccar.geocoder;
-import java.util.TimeZone;
+import jakarta.ws.rs.client.Client;
-public class DeviceSession {
+public class LocationIqGeocoder extends NominatimGeocoder {
- private final long deviceId;
+ private static final String DEFAULT_URL = "https://us1.locationiq.com/v1/reverse.php";
- public DeviceSession(long deviceId) {
- this.deviceId = deviceId;
- }
-
- public long getDeviceId() {
- return deviceId;
- }
-
- private TimeZone timeZone;
-
- public void setTimeZone(TimeZone timeZone) {
- this.timeZone = timeZone;
- }
-
- public TimeZone getTimeZone() {
- return timeZone;
+ public LocationIqGeocoder(
+ Client client, String url, String key, String language, int cacheSize, AddressFormat addressFormat) {
+ super(client, url != null ? url : DEFAULT_URL, key, language, cacheSize, addressFormat);
}
}
diff --git a/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java b/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java
index 8dc3f76f0..1b6c8adcc 100644
--- a/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java
@@ -16,8 +16,9 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class MapQuestGeocoder extends JsonGeocoder {
@@ -29,8 +30,8 @@ public class MapQuestGeocoder extends JsonGeocoder {
return url;
}
- public MapQuestGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) {
- super(formatUrl(url, key), cacheSize, addressFormat);
+ public MapQuestGeocoder(Client client, String url, String key, int cacheSize, AddressFormat addressFormat) {
+ super(client, formatUrl(url, key), cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/MapTilerGeocoder.java b/src/main/java/org/traccar/geocoder/MapTilerGeocoder.java
index 6b688a6e8..24c9da2ad 100644
--- a/src/main/java/org/traccar/geocoder/MapTilerGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/MapTilerGeocoder.java
@@ -15,13 +15,14 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class MapTilerGeocoder extends JsonGeocoder {
- public MapTilerGeocoder(String key, int cacheSize, AddressFormat addressFormat) {
- super("https://api.maptiler.com/geocoding/%2$f,%1$f.json?key=" + key, cacheSize, addressFormat);
+ public MapTilerGeocoder(Client client, String key, int cacheSize, AddressFormat addressFormat) {
+ super(client, "https://api.maptiler.com/geocoding/%2$f,%1$f.json?key=" + key, cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/MapboxGeocoder.java b/src/main/java/org/traccar/geocoder/MapboxGeocoder.java
index 9b987c9d8..9fa6b8d88 100644
--- a/src/main/java/org/traccar/geocoder/MapboxGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/MapboxGeocoder.java
@@ -15,9 +15,10 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
-import javax.json.JsonString;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonString;
+import jakarta.ws.rs.client.Client;
public class MapboxGeocoder extends JsonGeocoder {
@@ -25,8 +26,8 @@ public class MapboxGeocoder extends JsonGeocoder {
return "https://api.mapbox.com/geocoding/v5/mapbox.places/%2$f,%1$f.json?access_token=" + key;
}
- public MapboxGeocoder(String key, int cacheSize, AddressFormat addressFormat) {
- super(formatUrl(key), cacheSize, addressFormat);
+ public MapboxGeocoder(Client client, String key, int cacheSize, AddressFormat addressFormat) {
+ super(client, formatUrl(key), cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java b/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java
index 2b70708a1..b68db07bc 100644
--- a/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java
@@ -15,13 +15,14 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class MapmyIndiaGeocoder extends JsonGeocoder {
- public MapmyIndiaGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) {
- super(url + "/" + key + "/rev_geocode?lat=%f&lng=%f", cacheSize, addressFormat);
+ public MapmyIndiaGeocoder(Client client, String url, String key, int cacheSize, AddressFormat addressFormat) {
+ super(client, url + "/" + key + "/rev_geocode?lat=%f&lng=%f", cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/NominatimGeocoder.java b/src/main/java/org/traccar/geocoder/NominatimGeocoder.java
index 8db25bf15..1e26d0042 100644
--- a/src/main/java/org/traccar/geocoder/NominatimGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/NominatimGeocoder.java
@@ -15,7 +15,8 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonObject;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class NominatimGeocoder extends JsonGeocoder {
@@ -33,8 +34,9 @@ public class NominatimGeocoder extends JsonGeocoder {
return url;
}
- public NominatimGeocoder(String url, String key, String language, int cacheSize, AddressFormat addressFormat) {
- super(formatUrl(url, key, language), cacheSize, addressFormat);
+ public NominatimGeocoder(
+ Client client, String url, String key, String language, int cacheSize, AddressFormat addressFormat) {
+ super(client, formatUrl(url, key, language), cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java b/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java
index bbcc00cd0..4607fdc87 100644
--- a/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java
@@ -16,8 +16,9 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class OpenCageGeocoder extends JsonGeocoder {
@@ -32,8 +33,9 @@ public class OpenCageGeocoder extends JsonGeocoder {
return url;
}
- public OpenCageGeocoder(String url, String key, String language, int cacheSize, AddressFormat addressFormat) {
- super(formatUrl(url, key, language), cacheSize, addressFormat);
+ public OpenCageGeocoder(
+ Client client, String url, String key, String language, int cacheSize, AddressFormat addressFormat) {
+ super(client, formatUrl(url, key, language), cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/PositionStackGeocoder.java b/src/main/java/org/traccar/geocoder/PositionStackGeocoder.java
index 2674a68ca..4aed27fc5 100644
--- a/src/main/java/org/traccar/geocoder/PositionStackGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/PositionStackGeocoder.java
@@ -15,8 +15,9 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class PositionStackGeocoder extends JsonGeocoder {
@@ -24,8 +25,8 @@ public class PositionStackGeocoder extends JsonGeocoder {
return "http://api.positionstack.com/v1/reverse?access_key=" + key + "&query=%f,%f";
}
- public PositionStackGeocoder(String key, int cacheSize, AddressFormat addressFormat) {
- super(formatUrl(key), cacheSize, addressFormat);
+ public PositionStackGeocoder(Client client, String key, int cacheSize, AddressFormat addressFormat) {
+ super(client, formatUrl(key), cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geocoder/TestGeocoder.java b/src/main/java/org/traccar/geocoder/TestGeocoder.java
new file mode 100644
index 000000000..259f13c6c
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/TestGeocoder.java
@@ -0,0 +1,36 @@
+/*
+ * 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.geocoder;
+
+import org.traccar.database.StatisticsManager;
+
+public class TestGeocoder implements Geocoder {
+
+ @Override
+ public void setStatisticsManager(StatisticsManager statisticsManager) {
+ }
+
+ @Override
+ public String getAddress(double latitude, double longitude, ReverseGeocoderCallback callback) {
+ String address = String.format("Location %f, %f", latitude, longitude);
+ if (callback != null) {
+ callback.onSuccess(address);
+ return null;
+ }
+ return address;
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/TomTomGeocoder.java b/src/main/java/org/traccar/geocoder/TomTomGeocoder.java
index 232b24396..4d452fd43 100644
--- a/src/main/java/org/traccar/geocoder/TomTomGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/TomTomGeocoder.java
@@ -15,8 +15,9 @@
*/
package org.traccar.geocoder;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
public class TomTomGeocoder extends JsonGeocoder {
@@ -28,8 +29,8 @@ public class TomTomGeocoder extends JsonGeocoder {
return url;
}
- public TomTomGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) {
- super(formatUrl(url, key), cacheSize, addressFormat);
+ public TomTomGeocoder(Client client, String url, String key, int cacheSize, AddressFormat addressFormat) {
+ super(client, formatUrl(url, key), cacheSize, addressFormat);
}
@Override
diff --git a/src/main/java/org/traccar/geofence/GeofenceCircle.java b/src/main/java/org/traccar/geofence/GeofenceCircle.java
index 5d566f84e..59feb1730 100644
--- a/src/main/java/org/traccar/geofence/GeofenceCircle.java
+++ b/src/main/java/org/traccar/geofence/GeofenceCircle.java
@@ -18,7 +18,9 @@ package org.traccar.geofence;
import java.text.DecimalFormat;
import java.text.ParseException;
+import org.traccar.config.Config;
import org.traccar.helper.DistanceCalculator;
+import org.traccar.model.Geofence;
public class GeofenceCircle extends GeofenceGeometry {
@@ -44,7 +46,7 @@ public class GeofenceCircle extends GeofenceGeometry {
}
@Override
- public boolean containsPoint(double latitude, double longitude) {
+ public boolean containsPoint(Config config, Geofence geofence, double latitude, double longitude) {
return distanceFromCenter(latitude, longitude) <= radius;
}
diff --git a/src/main/java/org/traccar/geofence/GeofenceGeometry.java b/src/main/java/org/traccar/geofence/GeofenceGeometry.java
index 2c45c22af..fadabab1c 100644
--- a/src/main/java/org/traccar/geofence/GeofenceGeometry.java
+++ b/src/main/java/org/traccar/geofence/GeofenceGeometry.java
@@ -15,11 +15,14 @@
*/
package org.traccar.geofence;
+import org.traccar.config.Config;
+import org.traccar.model.Geofence;
+
import java.text.ParseException;
public abstract class GeofenceGeometry {
- public abstract boolean containsPoint(double latitude, double longitude);
+ public abstract boolean containsPoint(Config config, Geofence geofence, double latitude, double longitude);
public abstract double calculateArea();
diff --git a/src/main/java/org/traccar/geofence/GeofencePolygon.java b/src/main/java/org/traccar/geofence/GeofencePolygon.java
index cd2cbf16a..13f6658ef 100644
--- a/src/main/java/org/traccar/geofence/GeofencePolygon.java
+++ b/src/main/java/org/traccar/geofence/GeofencePolygon.java
@@ -19,6 +19,8 @@ import org.locationtech.spatial4j.context.SpatialContext;
import org.locationtech.spatial4j.context.jts.JtsSpatialContextFactory;
import org.locationtech.spatial4j.shape.ShapeFactory;
import org.locationtech.spatial4j.shape.jts.JtsShapeFactory;
+import org.traccar.config.Config;
+import org.traccar.model.Geofence;
import java.text.ParseException;
import java.util.ArrayList;
@@ -95,7 +97,7 @@ public class GeofencePolygon extends GeofenceGeometry {
}
@Override
- public boolean containsPoint(double latitude, double longitude) {
+ public boolean containsPoint(Config config, Geofence geofence, double latitude, double longitude) {
int polyCorners = coordinates.size();
int i;
diff --git a/src/main/java/org/traccar/geofence/GeofencePolyline.java b/src/main/java/org/traccar/geofence/GeofencePolyline.java
index 370bf99bb..d9c280ae4 100644
--- a/src/main/java/org/traccar/geofence/GeofencePolyline.java
+++ b/src/main/java/org/traccar/geofence/GeofencePolyline.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,23 +19,28 @@ package org.traccar.geofence;
import java.text.ParseException;
import java.util.ArrayList;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
import org.traccar.helper.DistanceCalculator;
+import org.traccar.model.Geofence;
public class GeofencePolyline extends GeofenceGeometry {
private ArrayList<Coordinate> coordinates;
- private double distance;
public GeofencePolyline() {
}
- public GeofencePolyline(String wkt, double distance) throws ParseException {
+ public GeofencePolyline(String wkt) throws ParseException {
fromWkt(wkt);
- this.distance = distance;
}
@Override
- public boolean containsPoint(double latitude, double longitude) {
+ public boolean containsPoint(Config config, Geofence geofence, double latitude, double longitude) {
+ double distance = geofence.getDouble("polylineDistance");
+ if (distance == 0) {
+ distance = config.getDouble(Keys.GEOFENCE_POLYLINE_DISTANCE);
+ }
for (int i = 1; i < coordinates.size(); i++) {
if (DistanceCalculator.distanceToLine(
latitude, longitude, coordinates.get(i - 1).getLat(), coordinates.get(i - 1).getLon(),
@@ -56,9 +61,9 @@ public class GeofencePolyline extends GeofenceGeometry {
StringBuilder buf = new StringBuilder();
buf.append("LINESTRING (");
for (Coordinate coordinate : coordinates) {
- buf.append(String.valueOf(coordinate.getLat()));
+ buf.append(coordinate.getLat());
buf.append(" ");
- buf.append(String.valueOf(coordinate.getLon()));
+ buf.append(coordinate.getLon());
buf.append(", ");
}
return buf.substring(0, buf.length() - 2) + ")";
@@ -105,8 +110,4 @@ public class GeofencePolyline extends GeofenceGeometry {
}
- public void setDistance(double distance) {
- this.distance = distance;
- }
-
}
diff --git a/src/main/java/org/traccar/geolocation/GoogleGeolocationProvider.java b/src/main/java/org/traccar/geolocation/GoogleGeolocationProvider.java
index 5901b47cd..9425e9111 100644
--- a/src/main/java/org/traccar/geolocation/GoogleGeolocationProvider.java
+++ b/src/main/java/org/traccar/geolocation/GoogleGeolocationProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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,12 +15,14 @@
*/
package org.traccar.geolocation;
+import jakarta.ws.rs.client.Client;
+
public class GoogleGeolocationProvider extends UniversalGeolocationProvider {
private static final String URL = "https://www.googleapis.com/geolocation/v1/geolocate";
- public GoogleGeolocationProvider(String key) {
- super(URL, key);
+ public GoogleGeolocationProvider(Client client, String key) {
+ super(client, URL, key);
}
}
diff --git a/src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java b/src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java
index c6a73a52b..7eb22dcca 100644
--- a/src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java
+++ b/src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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,12 +15,14 @@
*/
package org.traccar.geolocation;
+import jakarta.ws.rs.client.Client;
+
public class MozillaGeolocationProvider extends UniversalGeolocationProvider {
private static final String URL = "https://location.services.mozilla.com/v1/geolocate";
- public MozillaGeolocationProvider(String key) {
- super(URL, key != null ? key : "test");
+ public MozillaGeolocationProvider(Client client, String key) {
+ super(client, URL, key != null ? key : "test");
}
}
diff --git a/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java b/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java
index 2535970d3..72a05d10f 100644
--- a/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java
+++ b/src/main/java/org/traccar/geolocation/OpenCellIdGeolocationProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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,18 +15,20 @@
*/
package org.traccar.geolocation;
-import org.traccar.Context;
import org.traccar.model.CellTower;
import org.traccar.model.Network;
-import javax.json.JsonObject;
-import javax.ws.rs.client.InvocationCallback;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.InvocationCallback;
public class OpenCellIdGeolocationProvider implements GeolocationProvider {
- private String url;
+ private final Client client;
+ private final String url;
- public OpenCellIdGeolocationProvider(String url, String key) {
+ public OpenCellIdGeolocationProvider(Client client, String url, String key) {
+ this.client = client;
if (url == null) {
url = "http://opencellid.org/cell/get";
}
@@ -41,7 +43,7 @@ public class OpenCellIdGeolocationProvider implements GeolocationProvider {
String request = String.format(url, cellTower.getMobileCountryCode(), cellTower.getMobileNetworkCode(),
cellTower.getLocationAreaCode(), cellTower.getCellId());
- Context.getClient().target(request).request().async().get(new InvocationCallback<JsonObject>() {
+ client.target(request).request().async().get(new InvocationCallback<JsonObject>() {
@Override
public void completed(JsonObject json) {
if (json.containsKey("lat") && json.containsKey("lon")) {
diff --git a/src/main/java/org/traccar/geolocation/UniversalGeolocationProvider.java b/src/main/java/org/traccar/geolocation/UniversalGeolocationProvider.java
index 33cd84a47..9086d8ce3 100644
--- a/src/main/java/org/traccar/geolocation/UniversalGeolocationProvider.java
+++ b/src/main/java/org/traccar/geolocation/UniversalGeolocationProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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,26 +15,26 @@
*/
package org.traccar.geolocation;
-import org.traccar.Context;
import org.traccar.model.Network;
-import javax.json.JsonObject;
-import javax.ws.rs.client.AsyncInvoker;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.InvocationCallback;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.client.InvocationCallback;
public class UniversalGeolocationProvider implements GeolocationProvider {
+ private final Client client;
private final String url;
- public UniversalGeolocationProvider(String url, String key) {
+ public UniversalGeolocationProvider(Client client, String url, String key) {
+ this.client = client;
this.url = url + "?key=" + key;
}
@Override
public void getLocation(Network network, final LocationProviderCallback callback) {
- AsyncInvoker invoker = Context.getClient().target(url).request().async();
- invoker.post(Entity.json(network), new InvocationCallback<JsonObject>() {
+ client.target(url).request().async().post(Entity.json(network), new InvocationCallback<JsonObject>() {
@Override
public void completed(JsonObject json) {
if (json.containsKey("error")) {
diff --git a/src/main/java/org/traccar/geolocation/UnwiredGeolocationProvider.java b/src/main/java/org/traccar/geolocation/UnwiredGeolocationProvider.java
index 963bcb688..4f1c5617e 100644
--- a/src/main/java/org/traccar/geolocation/UnwiredGeolocationProvider.java
+++ b/src/main/java/org/traccar/geolocation/UnwiredGeolocationProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2018 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.
@@ -19,22 +19,23 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
-import org.traccar.Context;
import org.traccar.model.CellTower;
import org.traccar.model.Network;
import org.traccar.model.WifiAccessPoint;
-import javax.json.JsonObject;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.InvocationCallback;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.client.InvocationCallback;
import java.util.Collection;
public class UnwiredGeolocationProvider implements GeolocationProvider {
- private String url;
- private String key;
+ private final Client client;
+ private final String url;
+ private final String key;
- private ObjectMapper objectMapper;
+ private final ObjectMapper objectMapper;
private abstract static class NetworkMixIn {
@JsonProperty("mcc")
@@ -73,7 +74,8 @@ public class UnwiredGeolocationProvider implements GeolocationProvider {
abstract Integer getSignalStrength();
}
- public UnwiredGeolocationProvider(String url, String key) {
+ public UnwiredGeolocationProvider(Client client, String url, String key) {
+ this.client = client;
this.url = url;
this.key = key;
@@ -88,7 +90,7 @@ public class UnwiredGeolocationProvider implements GeolocationProvider {
ObjectNode json = objectMapper.valueToTree(network);
json.put("token", key);
- Context.getClient().target(url).request().async().post(Entity.json(json), new InvocationCallback<JsonObject>() {
+ client.target(url).request().async().post(Entity.json(json), new InvocationCallback<JsonObject>() {
@Override
public void completed(JsonObject json) {
if (json.getString("status").equals("error")) {
diff --git a/src/main/java/org/traccar/handler/AcknowledgementHandler.java b/src/main/java/org/traccar/handler/AcknowledgementHandler.java
new file mode 100644
index 000000000..4c1085998
--- /dev/null
+++ b/src/main/java/org/traccar/handler/AcknowledgementHandler.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.handler;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelOutboundHandlerAdapter;
+import io.netty.channel.ChannelPromise;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+public class AcknowledgementHandler extends ChannelOutboundHandlerAdapter {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AcknowledgementHandler.class);
+
+ public interface Event {
+ }
+
+ public static class EventReceived implements Event {
+ }
+
+ public static class EventDecoded implements Event {
+ private final Collection<Object> objects;
+
+ public EventDecoded(Collection<Object> objects) {
+ this.objects = objects;
+ }
+
+ public Collection<Object> getObjects() {
+ return objects;
+ }
+ }
+
+ public static class EventHandled implements Event {
+ private final Object object;
+
+ public EventHandled(Object object) {
+ this.object = object;
+ }
+
+ public Object getObject() {
+ return object;
+ }
+ }
+
+ private static final class Entry {
+ private final Object message;
+ private final ChannelPromise promise;
+
+ private Entry(Object message, ChannelPromise promise) {
+ this.message = message;
+ this.promise = promise;
+ }
+
+ public Object getMessage() {
+ return message;
+ }
+
+ public ChannelPromise getPromise() {
+ return promise;
+ }
+ }
+
+ private List<Entry> queue;
+ private final Set<Object> waiting = new HashSet<>();
+
+ @Override
+ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
+ List<Entry> output = new LinkedList<>();
+ synchronized (this) {
+ if (msg instanceof Event) {
+ if (msg instanceof EventReceived) {
+ LOGGER.debug("Event received");
+ if (queue == null) {
+ queue = new LinkedList<>();
+ }
+ } else if (msg instanceof EventDecoded) {
+ EventDecoded event = (EventDecoded) msg;
+ LOGGER.debug("Event decoded {}", event.getObjects().size());
+ waiting.addAll(event.getObjects());
+ } else if (msg instanceof EventHandled) {
+ EventHandled event = (EventHandled) msg;
+ LOGGER.debug("Event handled");
+ waiting.remove(event.getObject());
+ }
+ if (!(msg instanceof EventReceived) && waiting.isEmpty()) {
+ output.addAll(queue);
+ queue = null;
+ }
+ } else if (queue != null) {
+ LOGGER.debug("Message queued");
+ queue.add(new Entry(msg, promise));
+ } else {
+ LOGGER.debug("Message sent");
+ output.add(new Entry(msg, promise));
+ }
+ }
+ for (Entry entry : output) {
+ ctx.write(entry.getMessage(), entry.getPromise());
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java
index 153da29b9..042747359 100644
--- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java
+++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,56 +24,77 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.List;
import io.netty.channel.ChannelHandler;
-import org.apache.commons.jexl2.JexlEngine;
-import org.apache.commons.jexl2.JexlException;
-import org.apache.commons.jexl2.MapContext;
+import org.apache.commons.jexl3.JexlFeatures;
+import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.JexlBuilder;
+import org.apache.commons.jexl3.introspection.JexlSandbox;
+import org.apache.commons.jexl3.JexlException;
+import org.apache.commons.jexl3.MapContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.BaseDataHandler;
import org.traccar.config.Config;
import org.traccar.config.Keys;
-import org.traccar.database.AttributesManager;
-import org.traccar.database.IdentityManager;
import org.traccar.model.Attribute;
import org.traccar.model.Device;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+@Singleton
@ChannelHandler.Sharable
public class ComputedAttributesHandler extends BaseDataHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(ComputedAttributesHandler.class);
- private final IdentityManager identityManager;
- private final AttributesManager attributesManager;
+ private final CacheManager cacheManager;
private final JexlEngine engine;
+ private final JexlFeatures features;
+
private final boolean includeDeviceAttributes;
- public ComputedAttributesHandler(
- Config config, IdentityManager identityManager, AttributesManager attributesManager) {
- this.identityManager = identityManager;
- this.attributesManager = attributesManager;
- engine = new JexlEngine();
- engine.setStrict(true);
- engine.setFunctions(Collections.singletonMap("math", Math.class));
+ @Inject
+ public ComputedAttributesHandler(Config config, CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
+ JexlSandbox sandbox = new JexlSandbox(false);
+ sandbox.allow("com.safe.Functions");
+ sandbox.allow(Math.class.getName());
+ List.of(
+ Double.class, Float.class, Integer.class, Long.class, Short.class,
+ Character.class, Boolean.class, String.class, Byte.class)
+ .forEach((type) -> sandbox.allow(type.getName()));
+ features = new JexlFeatures()
+ .localVar(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES))
+ .loops(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOOPS))
+ .newInstance(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_NEW_INSTANCE_CREATION))
+ .structuredLiteral(true);
+ engine = new JexlBuilder()
+ .strict(true)
+ .namespaces(Collections.singletonMap("math", Math.class))
+ .sandbox(sandbox)
+ .create();
includeDeviceAttributes = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES);
}
private MapContext prepareContext(Position position) {
MapContext result = new MapContext();
if (includeDeviceAttributes) {
- Device device = identityManager.getById(position.getDeviceId());
+ Device device = cacheManager.getObject(Device.class, position.getDeviceId());
if (device != null) {
- for (Object key : device.getAttributes().keySet()) {
- result.set((String) key, device.getAttributes().get(key));
+ for (String key : device.getAttributes().keySet()) {
+ result.set(key, device.getAttributes().get(key));
}
}
}
Set<Method> methods = new HashSet<>(Arrays.asList(position.getClass().getMethods()));
- methods.removeAll(Arrays.asList(Object.class.getMethods()));
+ Arrays.asList(Object.class.getMethods()).forEach(methods::remove);
for (Method method : methods) {
if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) {
String name = Character.toLowerCase(method.getName().charAt(3)) + method.getName().substring(4);
@@ -82,8 +103,8 @@ public class ComputedAttributesHandler extends BaseDataHandler {
if (!method.getReturnType().equals(Map.class)) {
result.set(name, method.invoke(position));
} else {
- for (Object key : ((Map) method.invoke(position)).keySet()) {
- result.set((String) key, ((Map) method.invoke(position)).get(key));
+ for (Object key : ((Map<?, ?>) method.invoke(position)).keySet()) {
+ result.set((String) key, ((Map<?, ?>) method.invoke(position)).get(key));
}
}
} catch (IllegalAccessException | InvocationTargetException error) {
@@ -99,13 +120,14 @@ public class ComputedAttributesHandler extends BaseDataHandler {
*/
@Deprecated
public Object computeAttribute(Attribute attribute, Position position) throws JexlException {
- return engine.createExpression(attribute.getExpression()).evaluate(prepareContext(position));
+ return engine
+ .createScript(features, engine.createInfo(), attribute.getExpression())
+ .execute(prepareContext(position));
}
@Override
protected Position handlePosition(Position position) {
- Collection<Attribute> attributes = attributesManager.getItems(
- attributesManager.getAllDeviceItems(position.getDeviceId()));
+ Collection<Attribute> attributes = cacheManager.getDeviceObjects(position.getDeviceId(), Attribute.class);
for (Attribute attribute : attributes) {
if (attribute.getAttribute() != null) {
Object result = null;
@@ -116,17 +138,45 @@ public class ComputedAttributesHandler extends BaseDataHandler {
}
if (result != null) {
try {
- switch (attribute.getType()) {
- case "number":
- Number numberValue = (Number) result;
- position.getAttributes().put(attribute.getAttribute(), numberValue);
+ switch (attribute.getAttribute()) {
+ case "valid":
+ position.setValid((Boolean) result);
+ break;
+ case "latitude":
+ position.setLatitude(((Number) result).doubleValue());
+ break;
+ case "longitude":
+ position.setLongitude(((Number) result).doubleValue());
+ break;
+ case "altitude":
+ position.setAltitude(((Number) result).doubleValue());
break;
- case "boolean":
- Boolean booleanValue = (Boolean) result;
- position.getAttributes().put(attribute.getAttribute(), booleanValue);
+ case "speed":
+ position.setSpeed(((Number) result).doubleValue());
+ break;
+ case "course":
+ position.setCourse(((Number) result).doubleValue());
+ break;
+ case "address":
+ position.setAddress((String) result);
+ break;
+ case "accuracy":
+ position.setAccuracy(((Number) result).doubleValue());
break;
default:
- position.getAttributes().put(attribute.getAttribute(), result.toString());
+ switch (attribute.getType()) {
+ case "number":
+ Number numberValue = (Number) result;
+ position.getAttributes().put(attribute.getAttribute(), numberValue);
+ break;
+ case "boolean":
+ Boolean booleanValue = (Boolean) result;
+ position.getAttributes().put(attribute.getAttribute(), booleanValue);
+ break;
+ default:
+ position.getAttributes().put(attribute.getAttribute(), result.toString());
+ }
+ break;
}
} catch (ClassCastException error) {
LOGGER.warn("Attribute cast error", error);
diff --git a/src/main/java/org/traccar/handler/CopyAttributesHandler.java b/src/main/java/org/traccar/handler/CopyAttributesHandler.java
index f386116b0..42b438e41 100644
--- a/src/main/java/org/traccar/handler/CopyAttributesHandler.java
+++ b/src/main/java/org/traccar/handler/CopyAttributesHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,27 +18,39 @@ package org.traccar.handler;
import io.netty.channel.ChannelHandler;
import org.traccar.BaseDataHandler;
-import org.traccar.database.IdentityManager;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.AttributeUtil;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+@Singleton
@ChannelHandler.Sharable
public class CopyAttributesHandler extends BaseDataHandler {
- private IdentityManager identityManager;
+ private final boolean enabled;
+ private final CacheManager cacheManager;
- public CopyAttributesHandler(IdentityManager identityManager) {
- this.identityManager = identityManager;
+ @Inject
+ public CopyAttributesHandler(Config config, CacheManager cacheManager) {
+ enabled = config.getBoolean(Keys.PROCESSING_COPY_ATTRIBUTES_ENABLE);
+ this.cacheManager = cacheManager;
}
@Override
protected Position handlePosition(Position position) {
- String attributesString = identityManager.lookupAttributeString(
- position.getDeviceId(), "processing.copyAttributes", "", false, true);
- Position last = identityManager.getLastPosition(position.getDeviceId());
- if (last != null) {
- for (String attribute : attributesString.split("[ ,]")) {
- if (last.getAttributes().containsKey(attribute) && !position.getAttributes().containsKey(attribute)) {
- position.getAttributes().put(attribute, last.getAttributes().get(attribute));
+ if (enabled) {
+ String attributesString = AttributeUtil.lookup(
+ cacheManager, Keys.PROCESSING_COPY_ATTRIBUTES, position.getDeviceId());
+ Position last = cacheManager.getPosition(position.getDeviceId());
+ if (last != null && attributesString != null) {
+ for (String attribute : attributesString.split("[ ,]")) {
+ if (last.hasAttribute(attribute) && !position.hasAttribute(attribute)) {
+ position.getAttributes().put(attribute, last.getAttributes().get(attribute));
+ }
}
}
}
diff --git a/src/main/java/org/traccar/handler/DefaultDataHandler.java b/src/main/java/org/traccar/handler/DefaultDataHandler.java
index 9d8ea044d..cca6dcd0a 100644
--- a/src/main/java/org/traccar/handler/DefaultDataHandler.java
+++ b/src/main/java/org/traccar/handler/DefaultDataHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -19,25 +19,32 @@ import io.netty.channel.ChannelHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.BaseDataHandler;
-import org.traccar.database.DataManager;
import org.traccar.model.Position;
+import org.traccar.storage.Storage;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Request;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+@Singleton
@ChannelHandler.Sharable
public class DefaultDataHandler extends BaseDataHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDataHandler.class);
- private final DataManager dataManager;
+ private final Storage storage;
- public DefaultDataHandler(DataManager dataManager) {
- this.dataManager = dataManager;
+ @Inject
+ public DefaultDataHandler(Storage storage) {
+ this.storage = storage;
}
@Override
protected Position handlePosition(Position position) {
try {
- dataManager.addObject(position);
+ position.setId(storage.addObject(position, new Request(new Columns.Exclude("id"))));
} catch (Exception error) {
LOGGER.warn("Failed to store position", error);
}
diff --git a/src/main/java/org/traccar/handler/DistanceHandler.java b/src/main/java/org/traccar/handler/DistanceHandler.java
index 1e7e444f6..7fdefa1f4 100644
--- a/src/main/java/org/traccar/handler/DistanceHandler.java
+++ b/src/main/java/org/traccar/handler/DistanceHandler.java
@@ -1,6 +1,6 @@
/*
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2015 Amila Silva
- * Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,24 +20,28 @@ import io.netty.channel.ChannelHandler;
import org.traccar.BaseDataHandler;
import org.traccar.config.Config;
import org.traccar.config.Keys;
-import org.traccar.database.IdentityManager;
import org.traccar.helper.DistanceCalculator;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
import java.math.BigDecimal;
import java.math.RoundingMode;
+@Singleton
@ChannelHandler.Sharable
public class DistanceHandler extends BaseDataHandler {
- private final IdentityManager identityManager;
+ private final CacheManager cacheManager;
private final boolean filter;
private final int coordinatesMinError;
private final int coordinatesMaxError;
- public DistanceHandler(Config config, IdentityManager identityManager) {
- this.identityManager = identityManager;
+ @Inject
+ public DistanceHandler(Config config, CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
this.filter = config.getBoolean(Keys.COORDINATES_FILTER);
this.coordinatesMinError = config.getInteger(Keys.COORDINATES_MIN_ERROR);
this.coordinatesMaxError = config.getInteger(Keys.COORDINATES_MAX_ERROR);
@@ -47,15 +51,15 @@ public class DistanceHandler extends BaseDataHandler {
protected Position handlePosition(Position position) {
double distance = 0.0;
- if (position.getAttributes().containsKey(Position.KEY_DISTANCE)) {
+ if (position.hasAttribute(Position.KEY_DISTANCE)) {
distance = position.getDouble(Position.KEY_DISTANCE);
}
double totalDistance = 0.0;
- Position last = identityManager != null ? identityManager.getLastPosition(position.getDeviceId()) : null;
+ Position last = cacheManager.getPosition(position.getDeviceId());
if (last != null) {
totalDistance = last.getDouble(Position.KEY_TOTAL_DISTANCE);
- if (!position.getAttributes().containsKey(Position.KEY_DISTANCE)) {
+ if (!position.hasAttribute(Position.KEY_DISTANCE)) {
distance = DistanceCalculator.distance(
position.getLatitude(), position.getLongitude(),
last.getLatitude(), last.getLongitude());
diff --git a/src/main/java/org/traccar/handler/EngineHoursHandler.java b/src/main/java/org/traccar/handler/EngineHoursHandler.java
index 92da84e6b..621205b34 100644
--- a/src/main/java/org/traccar/handler/EngineHoursHandler.java
+++ b/src/main/java/org/traccar/handler/EngineHoursHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,22 +18,27 @@ package org.traccar.handler;
import io.netty.channel.ChannelHandler;
import org.traccar.BaseDataHandler;
-import org.traccar.database.IdentityManager;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+@Singleton
@ChannelHandler.Sharable
public class EngineHoursHandler extends BaseDataHandler {
- private final IdentityManager identityManager;
+ private final CacheManager cacheManager;
- public EngineHoursHandler(IdentityManager identityManager) {
- this.identityManager = identityManager;
+ @Inject
+ public EngineHoursHandler(CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
}
@Override
protected Position handlePosition(Position position) {
- if (!position.getAttributes().containsKey(Position.KEY_HOURS)) {
- Position last = identityManager.getLastPosition(position.getDeviceId());
+ if (!position.hasAttribute(Position.KEY_HOURS)) {
+ Position last = cacheManager.getPosition(position.getDeviceId());
if (last != null) {
long hours = last.getLong(Position.KEY_HOURS);
if (last.getBoolean(Position.KEY_IGNITION) && position.getBoolean(Position.KEY_IGNITION)) {
diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java
index e576a26b8..a15d3ffad 100644
--- a/src/main/java/org/traccar/handler/FilterHandler.java
+++ b/src/main/java/org/traccar/handler/FilterHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2014 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,51 +16,90 @@
package org.traccar.handler;
import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.BaseDataHandler;
-import org.traccar.Context;
import org.traccar.config.Config;
import org.traccar.config.Keys;
+import org.traccar.database.StatisticsManager;
import org.traccar.helper.UnitsConverter;
+import org.traccar.helper.model.AttributeUtil;
+import org.traccar.model.Calendar;
+import org.traccar.model.Device;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.storage.Storage;
import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Order;
+import org.traccar.storage.query.Request;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
import java.util.Date;
+@Singleton
@ChannelHandler.Sharable
-public class FilterHandler extends BaseDataHandler {
+public class FilterHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(FilterHandler.class);
- private boolean filterInvalid;
- private boolean filterZero;
- private boolean filterDuplicate;
- private long filterFuture;
- private boolean filterApproximate;
- private int filterAccuracy;
- private boolean filterStatic;
- private int filterDistance;
- private int filterMaxSpeed;
- private long filterMinPeriod;
- private boolean filterRelative;
- private long skipLimit;
- private boolean skipAttributes;
-
- public FilterHandler(Config config) {
+ private final boolean enabled;
+ private final boolean filterInvalid;
+ private final boolean filterZero;
+ private final boolean filterDuplicate;
+ private final boolean filterOutdated;
+ private final long filterFuture;
+ private final long filterPast;
+ private final boolean filterApproximate;
+ private final int filterAccuracy;
+ private final boolean filterStatic;
+ private final int filterDistance;
+ private final int filterMaxSpeed;
+ private final long filterMinPeriod;
+ private final int filterDailyLimit;
+ private final boolean filterRelative;
+ private final long skipLimit;
+ private final boolean skipAttributes;
+
+ private final CacheManager cacheManager;
+ private final Storage storage;
+ private final StatisticsManager statisticsManager;
+
+ @Inject
+ public FilterHandler(
+ Config config, CacheManager cacheManager, Storage storage, StatisticsManager statisticsManager) {
+ enabled = config.getBoolean(Keys.FILTER_ENABLE);
filterInvalid = config.getBoolean(Keys.FILTER_INVALID);
filterZero = config.getBoolean(Keys.FILTER_ZERO);
filterDuplicate = config.getBoolean(Keys.FILTER_DUPLICATE);
+ filterOutdated = config.getBoolean(Keys.FILTER_OUTDATED);
filterFuture = config.getLong(Keys.FILTER_FUTURE) * 1000;
+ filterPast = config.getLong(Keys.FILTER_PAST) * 1000;
filterAccuracy = config.getInteger(Keys.FILTER_ACCURACY);
filterApproximate = config.getBoolean(Keys.FILTER_APPROXIMATE);
filterStatic = config.getBoolean(Keys.FILTER_STATIC);
filterDistance = config.getInteger(Keys.FILTER_DISTANCE);
filterMaxSpeed = config.getInteger(Keys.FILTER_MAX_SPEED);
- filterMinPeriod = config.getInteger(Keys.FILTER_MIN_PERIOD) * 1000;
+ filterMinPeriod = config.getInteger(Keys.FILTER_MIN_PERIOD) * 1000L;
+ filterDailyLimit = config.getInteger(Keys.FILTER_DAILY_LIMIT);
filterRelative = config.getBoolean(Keys.FILTER_RELATIVE);
skipLimit = config.getLong(Keys.FILTER_SKIP_LIMIT) * 1000;
skipAttributes = config.getBoolean(Keys.FILTER_SKIP_ATTRIBUTES_ENABLE);
+ this.cacheManager = cacheManager;
+ this.storage = storage;
+ this.statisticsManager = statisticsManager;
+ }
+
+ private Position getPrecedingPosition(long deviceId, Date date) throws StorageException {
+ return storage.getObject(Position.class, new Request(
+ new Columns.All(),
+ new Condition.And(
+ new Condition.Equals("deviceId", deviceId),
+ new Condition.Compare("fixTime", "<=", "time", date)),
+ new Order("fixTime", true, 1)));
}
private boolean filterInvalid(Position position) {
@@ -76,7 +115,7 @@ public class FilterHandler extends BaseDataHandler {
private boolean filterDuplicate(Position position, Position last) {
if (filterDuplicate && last != null && position.getFixTime().equals(last.getFixTime())) {
for (String key : position.getAttributes().keySet()) {
- if (!last.getAttributes().containsKey(key)) {
+ if (!last.hasAttribute(key)) {
return false;
}
}
@@ -85,10 +124,18 @@ public class FilterHandler extends BaseDataHandler {
return false;
}
+ private boolean filterOutdated(Position position) {
+ return filterOutdated && position.getOutdated();
+ }
+
private boolean filterFuture(Position position) {
return filterFuture != 0 && position.getFixTime().getTime() > System.currentTimeMillis() + filterFuture;
}
+ private boolean filterPast(Position position) {
+ return filterPast != 0 && position.getFixTime().getTime() < System.currentTimeMillis() - filterPast;
+ }
+
private boolean filterAccuracy(Position position) {
return filterAccuracy != 0 && position.getAccuracy() > filterAccuracy;
}
@@ -125,6 +172,13 @@ public class FilterHandler extends BaseDataHandler {
return false;
}
+ private boolean filterDailyLimit(Position position) {
+ if (filterDailyLimit != 0) {
+ return statisticsManager.messageStoredCount(position.getDeviceId()) >= filterDailyLimit;
+ }
+ return false;
+ }
+
private boolean skipLimit(Position position, Position last) {
if (skipLimit != 0 && last != null) {
return (position.getServerTime().getTime() - last.getServerTime().getTime()) > skipLimit;
@@ -134,10 +188,9 @@ public class FilterHandler extends BaseDataHandler {
private boolean skipAttributes(Position position) {
if (skipAttributes) {
- String attributesString = Context.getIdentityManager().lookupAttributeString(
- position.getDeviceId(), "filter.skipAttributes", "", false, true);
- for (String attribute : attributesString.split("[ ,]")) {
- if (position.getAttributes().containsKey(attribute)) {
+ String string = AttributeUtil.lookup(cacheManager, Keys.FILTER_SKIP_ATTRIBUTES, position.getDeviceId());
+ for (String attribute : string.split("[ ,]")) {
+ if (position.hasAttribute(attribute)) {
return true;
}
}
@@ -145,7 +198,7 @@ public class FilterHandler extends BaseDataHandler {
return false;
}
- private boolean filter(Position position) {
+ protected boolean filter(Position position) {
StringBuilder filterType = new StringBuilder();
@@ -156,15 +209,24 @@ public class FilterHandler extends BaseDataHandler {
if (filterZero(position)) {
filterType.append("Zero ");
}
+ if (filterOutdated(position)) {
+ filterType.append("Outdated ");
+ }
if (filterFuture(position)) {
filterType.append("Future ");
}
+ if (filterPast(position)) {
+ filterType.append("Past ");
+ }
if (filterAccuracy(position)) {
filterType.append("Accuracy ");
}
if (filterApproximate(position)) {
filterType.append("Approximate ");
}
+ if (filterDailyLimit(position)) {
+ filterType.append("DailyLimit ");
+ }
// filter out excessive data
long deviceId = position.getDeviceId();
@@ -173,13 +235,13 @@ public class FilterHandler extends BaseDataHandler {
if (filterRelative) {
try {
Date newFixTime = position.getFixTime();
- preceding = Context.getDataManager().getPrecedingPosition(deviceId, newFixTime);
+ preceding = getPrecedingPosition(deviceId, newFixTime);
} catch (StorageException e) {
LOGGER.warn("Error retrieving preceding position; fallbacking to last received position.", e);
- preceding = getLastReceivedPosition(deviceId);
+ preceding = cacheManager.getPosition(deviceId);
}
} else {
- preceding = getLastReceivedPosition(deviceId);
+ preceding = cacheManager.getPosition(deviceId);
}
if (filterDuplicate(position, preceding) && !skipLimit(position, preceding) && !skipAttributes(position)) {
filterType.append("Duplicate ");
@@ -198,34 +260,34 @@ public class FilterHandler extends BaseDataHandler {
}
}
- if (filterType.length() > 0) {
-
- StringBuilder message = new StringBuilder();
- message.append("Position filtered by ");
- message.append(filterType.toString());
- message.append("filters from device: ");
- message.append(Context.getIdentityManager().getById(deviceId).getUniqueId());
+ Device device = cacheManager.getObject(Device.class, deviceId);
+ if (device.getCalendarId() > 0) {
+ Calendar calendar = cacheManager.getObject(Calendar.class, device.getCalendarId());
+ if (!calendar.checkMoment(position.getFixTime())) {
+ filterType.append("Calendar ");
+ }
+ }
- LOGGER.info(message.toString());
+ if (filterType.length() > 0) {
+ LOGGER.info("Position filtered by {}filters from device: {}", filterType, device.getUniqueId());
return true;
}
return false;
}
- private Position getLastReceivedPosition(long deviceId) {
- if (Context.getIdentityManager() != null) {
- return Context.getIdentityManager().getLastPosition(deviceId);
- }
- return null;
- }
-
@Override
- protected Position handlePosition(Position position) {
- if (filter(position)) {
- return null;
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ if (msg instanceof Position) {
+ Position position = (Position) msg;
+ if (enabled && filter(position)) {
+ ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(position));
+ } else {
+ ctx.fireChannelRead(position);
+ }
+ } else {
+ super.channelRead(ctx, msg);
}
- return position;
}
}
diff --git a/src/main/java/org/traccar/handler/GeocoderHandler.java b/src/main/java/org/traccar/handler/GeocoderHandler.java
index 614cf97d6..e4f240a90 100644
--- a/src/main/java/org/traccar/handler/GeocoderHandler.java
+++ b/src/main/java/org/traccar/handler/GeocoderHandler.java
@@ -20,12 +20,11 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.Context;
import org.traccar.config.Config;
import org.traccar.config.Keys;
-import org.traccar.database.IdentityManager;
import org.traccar.geocoder.Geocoder;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
@ChannelHandler.Sharable
public class GeocoderHandler extends ChannelInboundHandlerAdapter {
@@ -33,18 +32,17 @@ public class GeocoderHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(GeocoderHandler.class);
private final Geocoder geocoder;
- private final IdentityManager identityManager;
+ private final CacheManager cacheManager;
private final boolean ignorePositions;
private final boolean processInvalidPositions;
- private final int geocoderReuseDistance;
+ private final int reuseDistance;
- public GeocoderHandler(
- Config config, Geocoder geocoder, IdentityManager identityManager) {
+ public GeocoderHandler(Config config, Geocoder geocoder, CacheManager cacheManager) {
this.geocoder = geocoder;
- this.identityManager = identityManager;
- ignorePositions = Context.getConfig().getBoolean(Keys.GEOCODER_IGNORE_POSITIONS);
+ this.cacheManager = cacheManager;
+ ignorePositions = config.getBoolean(Keys.GEOCODER_IGNORE_POSITIONS);
processInvalidPositions = config.getBoolean(Keys.GEOCODER_PROCESS_INVALID_POSITIONS);
- geocoderReuseDistance = config.getInteger(Keys.GEOCODER_REUSE_DISTANCE, 0);
+ reuseDistance = config.getInteger(Keys.GEOCODER_REUSE_DISTANCE, 0);
}
@Override
@@ -52,10 +50,10 @@ public class GeocoderHandler extends ChannelInboundHandlerAdapter {
if (message instanceof Position && !ignorePositions) {
final Position position = (Position) message;
if (processInvalidPositions || position.getValid()) {
- if (geocoderReuseDistance != 0) {
- Position lastPosition = identityManager.getLastPosition(position.getDeviceId());
+ if (reuseDistance != 0) {
+ Position lastPosition = cacheManager.getPosition(position.getDeviceId());
if (lastPosition != null && lastPosition.getAddress() != null
- && position.getDouble(Position.KEY_DISTANCE) <= geocoderReuseDistance) {
+ && position.getDouble(Position.KEY_DISTANCE) <= reuseDistance) {
position.setAddress(lastPosition.getAddress());
ctx.fireChannelRead(position);
return;
diff --git a/src/main/java/org/traccar/handler/GeofenceHandler.java b/src/main/java/org/traccar/handler/GeofenceHandler.java
new file mode 100644
index 000000000..68bc6dbf0
--- /dev/null
+++ b/src/main/java/org/traccar/handler/GeofenceHandler.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.handler;
+
+import io.netty.channel.ChannelHandler;
+import org.traccar.BaseDataHandler;
+import org.traccar.config.Config;
+import org.traccar.helper.model.GeofenceUtil;
+import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.List;
+
+@Singleton
+@ChannelHandler.Sharable
+public class GeofenceHandler extends BaseDataHandler {
+
+ private final Config config;
+ private final CacheManager cacheManager;
+
+ @Inject
+ public GeofenceHandler(Config config, CacheManager cacheManager) {
+ this.config = config;
+ this.cacheManager = cacheManager;
+ }
+
+ @Override
+ protected Position handlePosition(Position position) {
+
+ List<Long> geofenceIds = GeofenceUtil.getCurrentGeofences(config, cacheManager, position);
+ if (!geofenceIds.isEmpty()) {
+ position.setGeofenceIds(geofenceIds);
+ }
+ return position;
+ }
+
+}
diff --git a/src/main/java/org/traccar/handler/GeolocationHandler.java b/src/main/java/org/traccar/handler/GeolocationHandler.java
index 0e78322c8..e7389f22d 100644
--- a/src/main/java/org/traccar/handler/GeolocationHandler.java
+++ b/src/main/java/org/traccar/handler/GeolocationHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -25,6 +25,7 @@ import org.traccar.config.Keys;
import org.traccar.database.StatisticsManager;
import org.traccar.geolocation.GeolocationProvider;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
@ChannelHandler.Sharable
public class GeolocationHandler extends ChannelInboundHandlerAdapter {
@@ -32,14 +33,19 @@ public class GeolocationHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(GeolocationHandler.class);
private final GeolocationProvider geolocationProvider;
+ private final CacheManager cacheManager;
private final StatisticsManager statisticsManager;
private final boolean processInvalidPositions;
+ private final boolean reuse;
public GeolocationHandler(
- Config config, GeolocationProvider geolocationProvider, StatisticsManager statisticsManager) {
+ Config config, GeolocationProvider geolocationProvider, CacheManager cacheManager,
+ StatisticsManager statisticsManager) {
this.geolocationProvider = geolocationProvider;
+ this.cacheManager = cacheManager;
this.statisticsManager = statisticsManager;
- this.processInvalidPositions = config.getBoolean(Keys.GEOLOCATION_PROCESS_INVALID_POSITIONS);
+ processInvalidPositions = config.getBoolean(Keys.GEOLOCATION_PROCESS_INVALID_POSITIONS);
+ reuse = config.getBoolean(Keys.GEOLOCATION_REUSE);
}
@Override
@@ -48,6 +54,17 @@ public class GeolocationHandler extends ChannelInboundHandlerAdapter {
final Position position = (Position) message;
if ((position.getOutdated() || processInvalidPositions && !position.getValid())
&& position.getNetwork() != null) {
+ if (reuse) {
+ Position lastPosition = cacheManager.getPosition(position.getDeviceId());
+ if (lastPosition != null && position.getNetwork().equals(lastPosition.getNetwork())) {
+ updatePosition(
+ position, lastPosition.getLatitude(), lastPosition.getLongitude(),
+ lastPosition.getAccuracy());
+ ctx.fireChannelRead(position);
+ return;
+ }
+ }
+
if (statisticsManager != null) {
statisticsManager.registerGeolocationRequest();
}
@@ -56,15 +73,7 @@ public class GeolocationHandler extends ChannelInboundHandlerAdapter {
new GeolocationProvider.LocationProviderCallback() {
@Override
public void onSuccess(double latitude, double longitude, double accuracy) {
- position.set(Position.KEY_APPROXIMATE, true);
- position.setValid(true);
- position.setFixTime(position.getDeviceTime());
- position.setLatitude(latitude);
- position.setLongitude(longitude);
- position.setAccuracy(accuracy);
- position.setAltitude(0);
- position.setSpeed(0);
- position.setCourse(0);
+ updatePosition(position, latitude, longitude, accuracy);
ctx.fireChannelRead(position);
}
@@ -82,4 +91,16 @@ public class GeolocationHandler extends ChannelInboundHandlerAdapter {
}
}
+ private void updatePosition(Position position, double latitude, double longitude, double accuracy) {
+ position.set(Position.KEY_APPROXIMATE, true);
+ position.setValid(true);
+ position.setFixTime(position.getDeviceTime());
+ position.setLatitude(latitude);
+ position.setLongitude(longitude);
+ position.setAccuracy(accuracy);
+ position.setAltitude(0);
+ position.setSpeed(0);
+ position.setCourse(0);
+ }
+
}
diff --git a/src/main/java/org/traccar/handler/HemisphereHandler.java b/src/main/java/org/traccar/handler/HemisphereHandler.java
index aff3d8a64..294e449db 100644
--- a/src/main/java/org/traccar/handler/HemisphereHandler.java
+++ b/src/main/java/org/traccar/handler/HemisphereHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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.
@@ -21,12 +21,17 @@ import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Position;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+@Singleton
@ChannelHandler.Sharable
public class HemisphereHandler extends BaseDataHandler {
private int latitudeFactor;
private int longitudeFactor;
+ @Inject
public HemisphereHandler(Config config) {
String latitudeHemisphere = config.getString(Keys.LOCATION_LATITUDE_HEMISPHERE);
if (latitudeHemisphere != null) {
@@ -36,7 +41,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/MotionHandler.java b/src/main/java/org/traccar/handler/MotionHandler.java
index e8051dd75..68a31a16a 100644
--- a/src/main/java/org/traccar/handler/MotionHandler.java
+++ b/src/main/java/org/traccar/handler/MotionHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,21 +18,31 @@ package org.traccar.handler;
import io.netty.channel.ChannelHandler;
import org.traccar.BaseDataHandler;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.AttributeUtil;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+@Singleton
@ChannelHandler.Sharable
public class MotionHandler extends BaseDataHandler {
- private double speedThreshold;
+ private final CacheManager cacheManager;
- public MotionHandler(double speedThreshold) {
- this.speedThreshold = speedThreshold;
+ @Inject
+ public MotionHandler(CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
}
@Override
protected Position handlePosition(Position position) {
- if (!position.getAttributes().containsKey(Position.KEY_MOTION)) {
- position.set(Position.KEY_MOTION, position.getSpeed() > speedThreshold);
+ if (!position.hasAttribute(Position.KEY_MOTION)) {
+ double threshold = AttributeUtil.lookup(
+ cacheManager, Keys.EVENT_MOTION_SPEED_THRESHOLD, position.getDeviceId());
+ position.set(Position.KEY_MOTION, position.getSpeed() > threshold);
}
return position;
}
diff --git a/src/main/java/org/traccar/handler/NetworkForwarderHandler.java b/src/main/java/org/traccar/handler/NetworkForwarderHandler.java
new file mode 100644
index 000000000..470e175ca
--- /dev/null
+++ b/src/main/java/org/traccar/handler/NetworkForwarderHandler.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.handler;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.channel.socket.DatagramChannel;
+import io.netty.channel.socket.DatagramPacket;
+import org.traccar.forward.NetworkForwarder;
+
+import jakarta.inject.Inject;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+
+public class NetworkForwarderHandler extends ChannelInboundHandlerAdapter {
+
+ private final int port;
+
+ private NetworkForwarder networkForwarder;
+
+ public NetworkForwarderHandler(int port) {
+ this.port = port;
+ }
+
+ @Inject
+ public void setNetworkForwarder(NetworkForwarder networkForwarder) {
+ this.networkForwarder = networkForwarder;
+ }
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ boolean datagram = ctx.channel() instanceof DatagramChannel;
+ SocketAddress remoteAddress;
+ ByteBuf buffer;
+ if (datagram) {
+ DatagramPacket message = (DatagramPacket) msg;
+ remoteAddress = message.recipient();
+ buffer = message.content();
+ } else {
+ remoteAddress = ctx.channel().remoteAddress();
+ buffer = (ByteBuf) msg;
+ }
+
+ byte[] data = new byte[buffer.readableBytes()];
+ buffer.getBytes(buffer.readerIndex(), data);
+ networkForwarder.forward((InetSocketAddress) remoteAddress, port, datagram, data);
+ super.channelRead(ctx, msg);
+ }
+
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+ if (!(ctx.channel() instanceof DatagramChannel)) {
+ networkForwarder.disconnect((InetSocketAddress) ctx.channel().remoteAddress());
+ }
+ super.channelInactive(ctx);
+ }
+
+}
diff --git a/src/main/java/org/traccar/handler/RemoteAddressHandler.java b/src/main/java/org/traccar/handler/RemoteAddressHandler.java
index c09b8c39a..61ada5b91 100644
--- a/src/main/java/org/traccar/handler/RemoteAddressHandler.java
+++ b/src/main/java/org/traccar/handler/RemoteAddressHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -18,22 +18,36 @@ package org.traccar.handler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
import org.traccar.model.Position;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
import java.net.InetSocketAddress;
+@Singleton
@ChannelHandler.Sharable
public class RemoteAddressHandler extends ChannelInboundHandlerAdapter {
+ private final boolean enabled;
+
+ @Inject
+ public RemoteAddressHandler(Config config) {
+ enabled = config.getBoolean(Keys.PROCESSING_REMOTE_ADDRESS_ENABLE);
+ }
+
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
- InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
- String hostAddress = remoteAddress != null ? remoteAddress.getAddress().getHostAddress() : null;
+ if (enabled) {
+ InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
+ String hostAddress = remoteAddress != null ? remoteAddress.getAddress().getHostAddress() : null;
- if (msg instanceof Position) {
- Position position = (Position) msg;
- position.set(Position.KEY_IP, hostAddress);
+ if (msg instanceof Position) {
+ Position position = (Position) msg;
+ position.set(Position.KEY_IP, hostAddress);
+ }
}
ctx.fireChannelRead(msg);
diff --git a/src/main/java/org/traccar/handler/SpeedLimitHandler.java b/src/main/java/org/traccar/handler/SpeedLimitHandler.java
index 65f2c9cfe..6edb6e912 100644
--- a/src/main/java/org/traccar/handler/SpeedLimitHandler.java
+++ b/src/main/java/org/traccar/handler/SpeedLimitHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2020 - 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.
@@ -23,6 +23,10 @@ import org.slf4j.LoggerFactory;
import org.traccar.model.Position;
import org.traccar.speedlimit.SpeedLimitProvider;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+@Singleton
@ChannelHandler.Sharable
public class SpeedLimitHandler extends ChannelInboundHandlerAdapter {
@@ -30,6 +34,7 @@ public class SpeedLimitHandler extends ChannelInboundHandlerAdapter {
private final SpeedLimitProvider speedLimitProvider;
+ @Inject
public SpeedLimitHandler(SpeedLimitProvider speedLimitProvider) {
this.speedLimitProvider = speedLimitProvider;
}
diff --git a/src/main/java/org/traccar/handler/StandardLoggingHandler.java b/src/main/java/org/traccar/handler/StandardLoggingHandler.java
index 13c5f8281..84492e2a5 100644
--- a/src/main/java/org/traccar/handler/StandardLoggingHandler.java
+++ b/src/main/java/org/traccar/handler/StandardLoggingHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 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.
@@ -23,6 +23,7 @@ import io.netty.channel.ChannelPromise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.NetworkMessage;
+import org.traccar.helper.NetworkUtil;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
@@ -63,7 +64,7 @@ public class StandardLoggingHandler extends ChannelDuplexHandler {
public void log(ChannelHandlerContext ctx, boolean downstream, SocketAddress remoteAddress, ByteBuf buf) {
StringBuilder message = new StringBuilder();
- message.append("[").append(ctx.channel().id().asShortText()).append(": ");
+ message.append("[").append(NetworkUtil.session(ctx.channel())).append(": ");
message.append(protocol);
if (downstream) {
message.append(" > ");
@@ -76,9 +77,8 @@ public class StandardLoggingHandler extends ChannelDuplexHandler {
} else {
message.append("unknown");
}
- message.append("]");
+ message.append("] ");
- message.append(" HEX: ");
message.append(ByteBufUtil.hexDump(buf));
LOGGER.info(message.toString());
diff --git a/src/main/java/org/traccar/handler/TimeHandler.java b/src/main/java/org/traccar/handler/TimeHandler.java
index 822c22a0a..3c3e17450 100644
--- a/src/main/java/org/traccar/handler/TimeHandler.java
+++ b/src/main/java/org/traccar/handler/TimeHandler.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.
@@ -19,24 +19,33 @@ import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Position;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
+@Singleton
@ChannelHandler.Sharable
public class TimeHandler extends ChannelInboundHandlerAdapter {
+ private final boolean enabled;
private final boolean useServerTime;
private final Set<String> protocols;
+ @Inject
public TimeHandler(Config config) {
- useServerTime = config.getString(Keys.TIME_OVERRIDE).equalsIgnoreCase("serverTime");
- String protocolList = Context.getConfig().getString(Keys.TIME_PROTOCOLS);
+ enabled = config.hasKey(Keys.TIME_OVERRIDE);
+ if (enabled) {
+ useServerTime = config.getString(Keys.TIME_OVERRIDE).equalsIgnoreCase("serverTime");
+ } else {
+ useServerTime = false;
+ }
+ String protocolList = config.getString(Keys.TIME_PROTOCOLS);
if (protocolList != null) {
protocols = new HashSet<>(Arrays.asList(protocolList.split("[, ]")));
} else {
@@ -47,7 +56,7 @@ public class TimeHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
- if (msg instanceof Position && (protocols == null
+ if (enabled && msg instanceof Position && (protocols == null
|| protocols.contains(ctx.pipeline().get(BaseProtocolDecoder.class).getProtocolName()))) {
Position position = (Position) msg;
diff --git a/src/main/java/org/traccar/handler/events/AlertEventHandler.java b/src/main/java/org/traccar/handler/events/AlertEventHandler.java
index 05dbc516e..531a0f957 100644
--- a/src/main/java/org/traccar/handler/events/AlertEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/AlertEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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.
@@ -21,18 +21,23 @@ import java.util.Map;
import io.netty.channel.ChannelHandler;
import org.traccar.config.Config;
import org.traccar.config.Keys;
-import org.traccar.database.IdentityManager;
import org.traccar.model.Event;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+@Singleton
@ChannelHandler.Sharable
public class AlertEventHandler extends BaseEventHandler {
- private final IdentityManager identityManager;
+ private final CacheManager cacheManager;
private final boolean ignoreDuplicateAlerts;
- public AlertEventHandler(Config config, IdentityManager identityManager) {
- this.identityManager = identityManager;
+ @Inject
+ public AlertEventHandler(Config config, CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
ignoreDuplicateAlerts = config.getBoolean(Keys.EVENT_IGNORE_DUPLICATE_ALERTS);
}
@@ -42,7 +47,7 @@ public class AlertEventHandler extends BaseEventHandler {
if (alarm != null) {
boolean ignoreAlert = false;
if (ignoreDuplicateAlerts) {
- Position lastPosition = identityManager.getLastPosition(position.getDeviceId());
+ Position lastPosition = cacheManager.getPosition(position.getDeviceId());
if (lastPosition != null && alarm.equals(lastPosition.getAttributes().get(Position.KEY_ALARM))) {
ignoreAlert = true;
}
diff --git a/src/main/java/org/traccar/handler/events/BaseEventHandler.java b/src/main/java/org/traccar/handler/events/BaseEventHandler.java
index 41f677f6c..4a4fb40ff 100644
--- a/src/main/java/org/traccar/handler/events/BaseEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/BaseEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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.
@@ -18,17 +18,26 @@ package org.traccar.handler.events;
import java.util.Map;
import org.traccar.BaseDataHandler;
-import org.traccar.Context;
+import org.traccar.database.NotificationManager;
import org.traccar.model.Event;
import org.traccar.model.Position;
+import jakarta.inject.Inject;
+
public abstract class BaseEventHandler extends BaseDataHandler {
+ private NotificationManager notificationManager;
+
+ @Inject
+ public void setNotificationManager(NotificationManager notificationManager) {
+ this.notificationManager = notificationManager;
+ }
+
@Override
protected Position handlePosition(Position position) {
Map<Event, Position> events = analyzePosition(position);
- if (events != null && Context.getNotificationManager() != null) {
- Context.getNotificationManager().updateEvents(events);
+ if (events != null && !events.isEmpty()) {
+ notificationManager.updateEvents(events);
}
return position;
}
diff --git a/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java b/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java
index 767cef3f6..08ae35fcd 100644
--- a/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2021 - 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.
@@ -18,32 +18,36 @@ package org.traccar.handler.events;
import io.netty.channel.ChannelHandler;
import org.traccar.config.Config;
import org.traccar.config.Keys;
-import org.traccar.database.IdentityManager;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Event;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
import java.util.Collections;
import java.util.Map;
+@Singleton
@ChannelHandler.Sharable
public class BehaviorEventHandler extends BaseEventHandler {
private final double accelerationThreshold;
private final double brakingThreshold;
- private final IdentityManager identityManager;
+ private final CacheManager cacheManager;
- public BehaviorEventHandler(Config config, IdentityManager identityManager) {
+ @Inject
+ public BehaviorEventHandler(Config config, CacheManager cacheManager) {
accelerationThreshold = config.getDouble(Keys.EVENT_BEHAVIOR_ACCELERATION_THRESHOLD);
brakingThreshold = config.getDouble(Keys.EVENT_BEHAVIOR_BRAKING_THRESHOLD);
- this.identityManager = identityManager;
+ this.cacheManager = cacheManager;
}
@Override
protected Map<Event, Position> analyzePosition(Position position) {
- Position lastPosition = identityManager.getLastPosition(position.getDeviceId());
+ Position lastPosition = cacheManager.getPosition(position.getDeviceId());
if (lastPosition != null && position.getFixTime().equals(lastPosition.getFixTime())) {
double acceleration = UnitsConverter.mpsFromKnots(position.getSpeed() - lastPosition.getSpeed()) * 1000
/ (position.getFixTime().getTime() - lastPosition.getFixTime().getTime());
diff --git a/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java b/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java
index 9b7ff554e..b70f8f33b 100644
--- a/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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.
@@ -22,9 +22,17 @@ import io.netty.channel.ChannelHandler;
import org.traccar.model.Event;
import org.traccar.model.Position;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+@Singleton
@ChannelHandler.Sharable
public class CommandResultEventHandler extends BaseEventHandler {
+ @Inject
+ public CommandResultEventHandler() {
+ }
+
@Override
protected Map<Event, Position> analyzePosition(Position position) {
Object commandResult = position.getAttributes().get(Position.KEY_RESULT);
diff --git a/src/main/java/org/traccar/handler/events/DriverEventHandler.java b/src/main/java/org/traccar/handler/events/DriverEventHandler.java
index 6fdf4246b..b68327983 100644
--- a/src/main/java/org/traccar/handler/events/DriverEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/DriverEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,32 +16,37 @@
*/
package org.traccar.handler.events;
-import java.util.Collections;
-import java.util.Map;
-
import io.netty.channel.ChannelHandler;
-import org.traccar.database.IdentityManager;
+import org.traccar.helper.model.PositionUtil;
import org.traccar.model.Event;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.Collections;
+import java.util.Map;
+@Singleton
@ChannelHandler.Sharable
public class DriverEventHandler extends BaseEventHandler {
- private final IdentityManager identityManager;
+ private final CacheManager cacheManager;
- public DriverEventHandler(IdentityManager identityManager) {
- this.identityManager = identityManager;
+ @Inject
+ public DriverEventHandler(CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
}
@Override
protected Map<Event, Position> analyzePosition(Position position) {
- if (!identityManager.isLatestPosition(position)) {
+ if (!PositionUtil.isLatest(cacheManager, position)) {
return null;
}
String driverUniqueId = position.getString(Position.KEY_DRIVER_UNIQUE_ID);
if (driverUniqueId != null) {
String oldDriverUniqueId = null;
- Position lastPosition = identityManager.getLastPosition(position.getDeviceId());
+ Position lastPosition = cacheManager.getPosition(position.getDeviceId());
if (lastPosition != null) {
oldDriverUniqueId = lastPosition.getString(Position.KEY_DRIVER_UNIQUE_ID);
}
diff --git a/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java b/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java
deleted file mode 100644
index 343a17311..000000000
--- a/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.traccar.handler.events;
-
-import io.netty.channel.ChannelHandler;
-import org.traccar.database.IdentityManager;
-import org.traccar.model.Device;
-import org.traccar.model.Event;
-import org.traccar.model.Position;
-
-import java.util.Collections;
-import java.util.Map;
-
-@ChannelHandler.Sharable
-public class FuelDropEventHandler extends BaseEventHandler {
-
- public static final String ATTRIBUTE_FUEL_DROP_THRESHOLD = "fuelDropThreshold";
-
- private final IdentityManager identityManager;
-
- public FuelDropEventHandler(IdentityManager identityManager) {
- this.identityManager = identityManager;
- }
-
- @Override
- protected Map<Event, Position> analyzePosition(Position position) {
-
- Device device = identityManager.getById(position.getDeviceId());
- if (device == null) {
- return null;
- }
- if (!identityManager.isLatestPosition(position)) {
- return null;
- }
-
- double fuelDropThreshold = identityManager
- .lookupAttributeDouble(device.getId(), ATTRIBUTE_FUEL_DROP_THRESHOLD, 0, true, false);
-
- if (fuelDropThreshold > 0) {
- Position lastPosition = identityManager.getLastPosition(position.getDeviceId());
- if (position.getAttributes().containsKey(Position.KEY_FUEL_LEVEL)
- && lastPosition != null && lastPosition.getAttributes().containsKey(Position.KEY_FUEL_LEVEL)) {
-
- double drop = lastPosition.getDouble(Position.KEY_FUEL_LEVEL)
- - 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);
- }
- }
- }
-
- return null;
- }
-
-}
diff --git a/src/main/java/org/traccar/handler/events/FuelEventHandler.java b/src/main/java/org/traccar/handler/events/FuelEventHandler.java
new file mode 100644
index 000000000..e5085ecc2
--- /dev/null
+++ b/src/main/java/org/traccar/handler/events/FuelEventHandler.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.handler.events;
+
+import io.netty.channel.ChannelHandler;
+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 jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.Map;
+
+@Singleton
+@ChannelHandler.Sharable
+public class FuelEventHandler extends BaseEventHandler {
+
+ private final CacheManager cacheManager;
+
+ @Inject
+ public FuelEventHandler(CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
+ }
+
+ @Override
+ protected Map<Event, Position> analyzePosition(Position position) {
+
+ Device device = cacheManager.getObject(Device.class, position.getDeviceId());
+ if (device == null) {
+ return null;
+ }
+ if (!PositionUtil.isLatest(cacheManager, position)) {
+ return null;
+ }
+
+ if (position.hasAttribute(Position.KEY_FUEL_LEVEL)) {
+ Position lastPosition = cacheManager.getPosition(position.getDeviceId());
+ if (lastPosition != null && lastPosition.hasAttribute(Position.KEY_FUEL_LEVEL)) {
+ double before = lastPosition.getDouble(Position.KEY_FUEL_LEVEL);
+ double after = position.getDouble(Position.KEY_FUEL_LEVEL);
+ double change = after - before;
+
+ if (change > 0) {
+ double threshold = AttributeUtil.lookup(
+ cacheManager, Keys.EVENT_FUEL_INCREASE_THRESHOLD, position.getDeviceId());
+ if (threshold > 0 && change >= threshold) {
+ return Map.of(new Event(Event.TYPE_DEVICE_FUEL_INCREASE, position), position);
+ }
+ } else if (change < 0) {
+ double threshold = AttributeUtil.lookup(
+ cacheManager, Keys.EVENT_FUEL_DROP_THRESHOLD, position.getDeviceId());
+ if (threshold > 0 && Math.abs(change) >= threshold) {
+ return Map.of(new Event(Event.TYPE_DEVICE_FUEL_DROP, position), position);
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java
index dae0c891f..dbe2b8118 100644
--- a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,75 +15,67 @@
*/
package org.traccar.handler.events;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
import io.netty.channel.ChannelHandler;
-import org.traccar.database.CalendarManager;
-import org.traccar.database.ConnectionManager;
-import org.traccar.database.GeofenceManager;
-import org.traccar.database.IdentityManager;
+import org.traccar.helper.model.PositionUtil;
import org.traccar.model.Calendar;
-import org.traccar.model.Device;
import org.traccar.model.Event;
+import org.traccar.model.Geofence;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Singleton
@ChannelHandler.Sharable
public class GeofenceEventHandler extends BaseEventHandler {
- private final IdentityManager identityManager;
- private final GeofenceManager geofenceManager;
- private final CalendarManager calendarManager;
- private final ConnectionManager connectionManager;
+ private final CacheManager cacheManager;
- public GeofenceEventHandler(
- IdentityManager identityManager, GeofenceManager geofenceManager, CalendarManager calendarManager,
- ConnectionManager connectionManager) {
- this.identityManager = identityManager;
- this.geofenceManager = geofenceManager;
- this.calendarManager = calendarManager;
- this.connectionManager = connectionManager;
+ @Inject
+ public GeofenceEventHandler(CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
}
@Override
protected Map<Event, Position> analyzePosition(Position position) {
- Device device = identityManager.getById(position.getDeviceId());
- if (device == null) {
- return null;
- }
- if (!identityManager.isLatestPosition(position) || !position.getValid()) {
+ if (!PositionUtil.isLatest(cacheManager, position)) {
return null;
}
- List<Long> currentGeofences = geofenceManager.getCurrentDeviceGeofences(position);
List<Long> oldGeofences = new ArrayList<>();
- if (device.getGeofenceIds() != null) {
- oldGeofences.addAll(device.getGeofenceIds());
+ Position lastPosition = cacheManager.getPosition(position.getDeviceId());
+ if (lastPosition != null && lastPosition.getGeofenceIds() != null) {
+ oldGeofences.addAll(lastPosition.getGeofenceIds());
}
- List<Long> newGeofences = new ArrayList<>(currentGeofences);
- newGeofences.removeAll(oldGeofences);
- oldGeofences.removeAll(currentGeofences);
- device.setGeofenceIds(currentGeofences);
- if (!oldGeofences.isEmpty() || !newGeofences.isEmpty()) {
- connectionManager.updateDevice(device);
+ List<Long> newGeofences = new ArrayList<>();
+ if (position.getGeofenceIds() != null) {
+ newGeofences.addAll(position.getGeofenceIds());
+ newGeofences.removeAll(oldGeofences);
+ oldGeofences.removeAll(position.getGeofenceIds());
}
Map<Event, Position> events = new HashMap<>();
for (long geofenceId : oldGeofences) {
- long calendarId = geofenceManager.getById(geofenceId).getCalendarId();
- Calendar calendar = calendarId != 0 ? calendarManager.getById(calendarId) : null;
- if (calendar == null || calendar.checkMoment(position.getFixTime())) {
- Event event = new Event(Event.TYPE_GEOFENCE_EXIT, position);
- event.setGeofenceId(geofenceId);
- events.put(event, position);
+ Geofence geofence = cacheManager.getObject(Geofence.class, geofenceId);
+ if (geofence != null) {
+ long calendarId = geofence.getCalendarId();
+ Calendar calendar = calendarId != 0 ? cacheManager.getObject(Calendar.class, calendarId) : null;
+ if (calendar == null || calendar.checkMoment(position.getFixTime())) {
+ Event event = new Event(Event.TYPE_GEOFENCE_EXIT, position);
+ event.setGeofenceId(geofenceId);
+ events.put(event, position);
+ }
}
}
for (long geofenceId : newGeofences) {
- long calendarId = geofenceManager.getById(geofenceId).getCalendarId();
- Calendar calendar = calendarId != 0 ? calendarManager.getById(calendarId) : null;
+ long calendarId = cacheManager.getObject(Geofence.class, geofenceId).getCalendarId();
+ Calendar calendar = calendarId != 0 ? cacheManager.getObject(Calendar.class, calendarId) : null;
if (calendar == null || calendar.checkMoment(position.getFixTime())) {
Event event = new Event(Event.TYPE_GEOFENCE_ENTER, position);
event.setGeofenceId(geofenceId);
diff --git a/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java b/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java
index 69df9a46b..ba4159a42 100644
--- a/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,34 +20,40 @@ import java.util.Collections;
import java.util.Map;
import io.netty.channel.ChannelHandler;
-import org.traccar.database.IdentityManager;
+import org.traccar.helper.model.PositionUtil;
import org.traccar.model.Device;
import org.traccar.model.Event;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+@Singleton
@ChannelHandler.Sharable
public class IgnitionEventHandler extends BaseEventHandler {
- private final IdentityManager identityManager;
+ private final CacheManager cacheManager;
- public IgnitionEventHandler(IdentityManager identityManager) {
- this.identityManager = identityManager;
+ @Inject
+ public IgnitionEventHandler(CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
}
@Override
protected Map<Event, Position> analyzePosition(Position position) {
- Device device = identityManager.getById(position.getDeviceId());
- if (device == null || !identityManager.isLatestPosition(position)) {
+ Device device = cacheManager.getObject(Device.class, position.getDeviceId());
+ if (device == null || !PositionUtil.isLatest(cacheManager, position)) {
return null;
}
Map<Event, Position> result = null;
- if (position.getAttributes().containsKey(Position.KEY_IGNITION)) {
+ if (position.hasAttribute(Position.KEY_IGNITION)) {
boolean ignition = position.getBoolean(Position.KEY_IGNITION);
- Position lastPosition = identityManager.getLastPosition(position.getDeviceId());
- if (lastPosition != null && lastPosition.getAttributes().containsKey(Position.KEY_IGNITION)) {
+ Position lastPosition = cacheManager.getPosition(position.getDeviceId());
+ if (lastPosition != null && lastPosition.hasAttribute(Position.KEY_IGNITION)) {
boolean oldIgnition = lastPosition.getBoolean(Position.KEY_IGNITION);
if (ignition && !oldIgnition) {
diff --git a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java
index 0f960ad1f..6c4271ce2 100644
--- a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,48 +20,46 @@ import java.util.HashMap;
import java.util.Map;
import io.netty.channel.ChannelHandler;
-import org.traccar.database.IdentityManager;
-import org.traccar.database.MaintenancesManager;
import org.traccar.model.Event;
import org.traccar.model.Maintenance;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+@Singleton
@ChannelHandler.Sharable
public class MaintenanceEventHandler extends BaseEventHandler {
- private final IdentityManager identityManager;
- private final MaintenancesManager maintenancesManager;
+ private final CacheManager cacheManager;
- public MaintenanceEventHandler(IdentityManager identityManager, MaintenancesManager maintenancesManager) {
- this.identityManager = identityManager;
- this.maintenancesManager = maintenancesManager;
+ @Inject
+ public MaintenanceEventHandler(CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
}
@Override
protected Map<Event, Position> analyzePosition(Position position) {
- if (identityManager.getById(position.getDeviceId()) == null
- || !identityManager.isLatestPosition(position)) {
- return null;
- }
-
- Position lastPosition = identityManager.getLastPosition(position.getDeviceId());
- if (lastPosition == null) {
+ Position lastPosition = cacheManager.getPosition(position.getDeviceId());
+ if (lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) < 0) {
return null;
}
Map<Event, Position> events = new HashMap<>();
- for (long maintenanceId : maintenancesManager.getAllDeviceItems(position.getDeviceId())) {
- Maintenance maintenance = maintenancesManager.getById(maintenanceId);
+ for (Maintenance maintenance : cacheManager.getDeviceObjects(position.getDeviceId(), Maintenance.class)) {
if (maintenance.getPeriod() != 0) {
double oldValue = lastPosition.getDouble(maintenance.getType());
double newValue = position.getDouble(maintenance.getType());
- if (oldValue != 0.0 && newValue != 0.0
- && (long) ((oldValue - maintenance.getStart()) / maintenance.getPeriod())
+ if (oldValue != 0.0 && newValue != 0.0 && newValue >= maintenance.getStart()) {
+ if (oldValue < maintenance.getStart()
+ || (long) ((oldValue - maintenance.getStart()) / maintenance.getPeriod())
< (long) ((newValue - maintenance.getStart()) / maintenance.getPeriod())) {
- Event event = new Event(Event.TYPE_MAINTENANCE, position);
- event.setMaintenanceId(maintenanceId);
- event.set(maintenance.getType(), newValue);
- events.put(event, position);
+ Event event = new Event(Event.TYPE_MAINTENANCE, position);
+ event.setMaintenanceId(maintenance.getId());
+ event.set(maintenance.getType(), newValue);
+ events.put(event, position);
+ }
}
}
}
diff --git a/src/main/java/org/traccar/handler/events/MediaEventHandler.java b/src/main/java/org/traccar/handler/events/MediaEventHandler.java
new file mode 100644
index 000000000..52d8e6961
--- /dev/null
+++ b/src/main/java/org/traccar/handler/events/MediaEventHandler.java
@@ -0,0 +1,49 @@
+/*
+ * 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.handler.events;
+
+import io.netty.channel.ChannelHandler;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Singleton
+@ChannelHandler.Sharable
+public class MediaEventHandler extends BaseEventHandler {
+
+ @Inject
+ public MediaEventHandler() {
+ }
+
+ @Override
+ protected Map<Event, Position> analyzePosition(Position position) {
+ return Stream.of(Position.KEY_IMAGE, Position.KEY_VIDEO, Position.KEY_AUDIO)
+ .filter(position::hasAttribute)
+ .map(type -> {
+ Event event = new Event(Event.TYPE_MEDIA, position);
+ event.set("media", type);
+ event.set("file", position.getString(type));
+ return event;
+ })
+ .collect(Collectors.toMap(event -> event, event -> position));
+ }
+
+}
diff --git a/src/main/java/org/traccar/handler/events/MotionEventHandler.java b/src/main/java/org/traccar/handler/events/MotionEventHandler.java
index db276f32b..15902d6d4 100644
--- a/src/main/java/org/traccar/handler/events/MotionEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/MotionEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,120 +16,73 @@
*/
package org.traccar.handler.events;
-import java.util.Collections;
-import java.util.Map;
-
import io.netty.channel.ChannelHandler;
-import org.traccar.database.DeviceManager;
-import org.traccar.database.IdentityManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.AttributeUtil;
+import org.traccar.helper.model.PositionUtil;
import org.traccar.model.Device;
-import org.traccar.model.DeviceState;
import org.traccar.model.Event;
import org.traccar.model.Position;
-import org.traccar.reports.ReportUtils;
-import org.traccar.reports.model.TripsConfig;
+import org.traccar.reports.common.TripsConfig;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.session.state.MotionProcessor;
+import org.traccar.session.state.MotionState;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.Collections;
+import java.util.Map;
+@Singleton
@ChannelHandler.Sharable
public class MotionEventHandler extends BaseEventHandler {
- private final IdentityManager identityManager;
- private final DeviceManager deviceManager;
- private final TripsConfig tripsConfig;
-
- public MotionEventHandler(IdentityManager identityManager, DeviceManager deviceManager, TripsConfig tripsConfig) {
- this.identityManager = identityManager;
- this.deviceManager = deviceManager;
- this.tripsConfig = tripsConfig;
- }
-
- private Map<Event, Position> newEvent(DeviceState deviceState, boolean newMotion) {
- String eventType = newMotion ? Event.TYPE_DEVICE_MOVING : Event.TYPE_DEVICE_STOPPED;
- Position position = deviceState.getMotionPosition();
- Event event = new Event(eventType, position);
- deviceState.setMotionState(newMotion);
- deviceState.setMotionPosition(null);
- return Collections.singletonMap(event, position);
- }
+ private static final Logger LOGGER = LoggerFactory.getLogger(MotionEventHandler.class);
- public Map<Event, Position> updateMotionState(DeviceState deviceState) {
- Map<Event, Position> result = null;
- if (deviceState.getMotionState() != null && deviceState.getMotionPosition() != null) {
- boolean newMotion = !deviceState.getMotionState();
- Position motionPosition = deviceState.getMotionPosition();
- long currentTime = System.currentTimeMillis();
- long motionTime = motionPosition.getFixTime().getTime()
- + (newMotion ? tripsConfig.getMinimalTripDuration() : tripsConfig.getMinimalParkingDuration());
- if (motionTime <= currentTime) {
- result = newEvent(deviceState, newMotion);
- }
- }
- return result;
- }
+ private final CacheManager cacheManager;
+ private final Storage storage;
- public Map<Event, Position> updateMotionState(DeviceState deviceState, Position position) {
- return updateMotionState(deviceState, position, position.getBoolean(Position.KEY_MOTION));
- }
-
- public Map<Event, Position> updateMotionState(DeviceState deviceState, Position position, boolean newMotion) {
- Map<Event, Position> result = null;
- Boolean oldMotion = deviceState.getMotionState();
-
- long currentTime = position.getFixTime().getTime();
- if (newMotion != oldMotion) {
- if (deviceState.getMotionPosition() == null) {
- deviceState.setMotionPosition(position);
- }
- } else {
- deviceState.setMotionPosition(null);
- }
-
- Position motionPosition = deviceState.getMotionPosition();
- if (motionPosition != null) {
- long motionTime = motionPosition.getFixTime().getTime();
- double distance = ReportUtils.calculateDistance(motionPosition, position, false);
- Boolean ignition = null;
- if (tripsConfig.getUseIgnition()
- && position.getAttributes().containsKey(Position.KEY_IGNITION)) {
- ignition = position.getBoolean(Position.KEY_IGNITION);
- }
- if (newMotion) {
- if (motionTime + tripsConfig.getMinimalTripDuration() <= currentTime
- || distance >= tripsConfig.getMinimalTripDistance()) {
- result = newEvent(deviceState, newMotion);
- }
- } else {
- if (motionTime + tripsConfig.getMinimalParkingDuration() <= currentTime
- || ignition != null && !ignition) {
- result = newEvent(deviceState, newMotion);
- }
- }
- }
- return result;
+ @Inject
+ public MotionEventHandler(CacheManager cacheManager, Storage storage) {
+ this.cacheManager = cacheManager;
+ this.storage = storage;
}
@Override
protected Map<Event, Position> analyzePosition(Position position) {
long deviceId = position.getDeviceId();
- Device device = identityManager.getById(deviceId);
- if (device == null) {
+ Device device = cacheManager.getObject(Device.class, deviceId);
+ if (device == null || !PositionUtil.isLatest(cacheManager, position)) {
return null;
}
- if (!identityManager.isLatestPosition(position)
- || !tripsConfig.getProcessInvalidPositions() && !position.getValid()) {
+ boolean processInvalid = AttributeUtil.lookup(
+ cacheManager, Keys.EVENT_MOTION_PROCESS_INVALID_POSITIONS, deviceId);
+ if (!processInvalid && !position.getValid()) {
return null;
}
- Map<Event, Position> result = null;
- DeviceState deviceState = deviceManager.getDeviceState(deviceId);
-
- if (deviceState.getMotionState() == null) {
- deviceState.setMotionState(position.getBoolean(Position.KEY_MOTION));
- } else {
- result = updateMotionState(deviceState, position);
+ TripsConfig tripsConfig = new TripsConfig(new AttributeUtil.CacheProvider(cacheManager, deviceId));
+ MotionState state = MotionState.fromDevice(device);
+ MotionProcessor.updateState(state, position, position.getBoolean(Position.KEY_MOTION), tripsConfig);
+ if (state.isChanged()) {
+ state.toDevice(device);
+ try {
+ storage.updateObject(device, new Request(
+ new Columns.Include("motionStreak", "motionState", "motionTime", "motionDistance"),
+ new Condition.Equals("id", device.getId())));
+ } catch (StorageException e) {
+ LOGGER.warn("Update device motion error", e);
+ }
}
- deviceManager.setDeviceState(deviceId, deviceState);
- return result;
+ return state.getEvent() != null ? Collections.singletonMap(state.getEvent(), position) : null;
}
}
diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java
index 347ad9005..3bb5f713c 100644
--- a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java
+++ b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,111 +16,67 @@
*/
package org.traccar.handler.events;
-import java.util.Collections;
-import java.util.Map;
-
import io.netty.channel.ChannelHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.traccar.config.Config;
import org.traccar.config.Keys;
-import org.traccar.database.DeviceManager;
-import org.traccar.database.GeofenceManager;
+import org.traccar.helper.model.AttributeUtil;
+import org.traccar.helper.model.PositionUtil;
import org.traccar.model.Device;
-import org.traccar.model.DeviceState;
import org.traccar.model.Event;
import org.traccar.model.Geofence;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.session.state.OverspeedProcessor;
+import org.traccar.session.state.OverspeedState;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.Collections;
+import java.util.Map;
+@Singleton
@ChannelHandler.Sharable
public class OverspeedEventHandler extends BaseEventHandler {
- public static final String ATTRIBUTE_SPEED = "speed";
- public static final String ATTRIBUTE_SPEED_LIMIT = "speedLimit";
+ private static final Logger LOGGER = LoggerFactory.getLogger(OverspeedEventHandler.class);
- private final DeviceManager deviceManager;
- private final GeofenceManager geofenceManager;
+ private final CacheManager cacheManager;
+ private final Storage storage;
- private final boolean notRepeat;
private final long minimalDuration;
private final boolean preferLowest;
+ private final double multiplier;
- public OverspeedEventHandler(Config config, DeviceManager deviceManager, GeofenceManager geofenceManager) {
- this.deviceManager = deviceManager;
- this.geofenceManager = geofenceManager;
- notRepeat = config.getBoolean(Keys.EVENT_OVERSPEED_NOT_REPEAT);
+ @Inject
+ public OverspeedEventHandler(
+ Config config, CacheManager cacheManager, Storage storage) {
+ this.cacheManager = cacheManager;
+ this.storage = storage;
minimalDuration = config.getLong(Keys.EVENT_OVERSPEED_MINIMAL_DURATION) * 1000;
preferLowest = config.getBoolean(Keys.EVENT_OVERSPEED_PREFER_LOWEST);
- }
-
- private Map<Event, Position> newEvent(DeviceState deviceState, double speedLimit) {
- 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.setGeofenceId(deviceState.getOverspeedGeofenceId());
- deviceState.setOverspeedState(notRepeat);
- deviceState.setOverspeedPosition(null);
- deviceState.setOverspeedGeofenceId(0);
- return Collections.singletonMap(event, position);
- }
-
- public Map<Event, Position> updateOverspeedState(DeviceState deviceState, double speedLimit) {
- Map<Event, Position> result = null;
- if (deviceState.getOverspeedState() != null && !deviceState.getOverspeedState()
- && deviceState.getOverspeedPosition() != null && speedLimit != 0) {
- long currentTime = System.currentTimeMillis();
- Position overspeedPosition = deviceState.getOverspeedPosition();
- long overspeedTime = overspeedPosition.getFixTime().getTime();
- if (overspeedTime + minimalDuration <= currentTime) {
- result = newEvent(deviceState, speedLimit);
- }
- }
- return result;
- }
-
- public Map<Event, Position> updateOverspeedState(
- DeviceState deviceState, Position position, double speedLimit, long geofenceId) {
- Map<Event, Position> result = null;
-
- Boolean oldOverspeed = deviceState.getOverspeedState();
-
- long currentTime = position.getFixTime().getTime();
- boolean newOverspeed = position.getSpeed() > speedLimit;
- if (newOverspeed && !oldOverspeed) {
- if (deviceState.getOverspeedPosition() == null) {
- deviceState.setOverspeedPosition(position);
- deviceState.setOverspeedGeofenceId(geofenceId);
- }
- } else if (oldOverspeed && !newOverspeed) {
- deviceState.setOverspeedState(false);
- deviceState.setOverspeedPosition(null);
- deviceState.setOverspeedGeofenceId(0);
- } else {
- deviceState.setOverspeedPosition(null);
- deviceState.setOverspeedGeofenceId(0);
- }
- Position overspeedPosition = deviceState.getOverspeedPosition();
- if (overspeedPosition != null) {
- long overspeedTime = overspeedPosition.getFixTime().getTime();
- if (newOverspeed && overspeedTime + minimalDuration <= currentTime) {
- result = newEvent(deviceState, speedLimit);
- }
- }
- return result;
+ multiplier = config.getDouble(Keys.EVENT_OVERSPEED_THRESHOLD_MULTIPLIER);
}
@Override
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) {
@@ -130,11 +86,11 @@ public class OverspeedEventHandler extends BaseEventHandler {
double geofenceSpeedLimit = 0;
long overspeedGeofenceId = 0;
- if (geofenceManager != null && device.getGeofenceIds() != null) {
- for (long geofenceId : device.getGeofenceIds()) {
- Geofence geofence = geofenceManager.getById(geofenceId);
+ if (position.getGeofenceIds() != null) {
+ for (long geofenceId : position.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) {
@@ -152,18 +108,19 @@ public class OverspeedEventHandler extends BaseEventHandler {
return null;
}
- Map<Event, Position> result = null;
- DeviceState deviceState = deviceManager.getDeviceState(deviceId);
-
- if (deviceState.getOverspeedState() == null) {
- deviceState.setOverspeedState(position.getSpeed() > speedLimit);
- deviceState.setOverspeedGeofenceId(position.getSpeed() > speedLimit ? overspeedGeofenceId : 0);
- } else {
- result = updateOverspeedState(deviceState, position, speedLimit, overspeedGeofenceId);
+ OverspeedState state = OverspeedState.fromDevice(device);
+ OverspeedProcessor.updateState(state, position, speedLimit, multiplier, minimalDuration, overspeedGeofenceId);
+ if (state.isChanged()) {
+ state.toDevice(device);
+ try {
+ storage.updateObject(device, new Request(
+ new Columns.Include("overspeedState", "overspeedTime", "overspeedGeofenceId"),
+ new Condition.Equals("id", device.getId())));
+ } catch (StorageException e) {
+ LOGGER.warn("Update device overspeed error", e);
+ }
}
-
- deviceManager.setDeviceState(deviceId, deviceState);
- return result;
+ return state.getEvent() != null ? Collections.singletonMap(state.getEvent(), position) : null;
}
}
diff --git a/src/main/java/org/traccar/helper/BitUtil.java b/src/main/java/org/traccar/helper/BitUtil.java
index b6108edff..829ddebc9 100644
--- a/src/main/java/org/traccar/helper/BitUtil.java
+++ b/src/main/java/org/traccar/helper/BitUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -21,7 +21,7 @@ public final class BitUtil {
}
public static boolean check(long number, int index) {
- return (number & (1 << index)) != 0;
+ return (number & (1L << index)) != 0;
}
public static int between(int number, int from, int to) {
diff --git a/src/main/java/org/traccar/helper/BufferUtil.java b/src/main/java/org/traccar/helper/BufferUtil.java
index 9485c17c6..12c31ba9d 100644
--- a/src/main/java/org/traccar/helper/BufferUtil.java
+++ b/src/main/java/org/traccar/helper/BufferUtil.java
@@ -27,6 +27,24 @@ public final class BufferUtil {
private BufferUtil() {
}
+ public static int readSignedMagnitudeInt(ByteBuf buffer) {
+ long value = buffer.readUnsignedInt();
+ int result = (int) BitUtil.to(value, 31);
+ return BitUtil.check(value, 31) ? -result : result;
+ }
+
+ public static int indexOf(ByteBuf buffer, int fromIndex, int toIndex, byte value, int count) {
+ int startIndex = fromIndex;
+ for (int i = 0; i < count; i++) {
+ int result = buffer.indexOf(startIndex, toIndex, value);
+ if (result < 0 || i == count - 1) {
+ return result;
+ }
+ startIndex = result + 1;
+ }
+ return -1;
+ }
+
public static int indexOf(String needle, ByteBuf haystack) {
return indexOf(needle, haystack, haystack.readerIndex(), haystack.writerIndex());
}
@@ -41,16 +59,28 @@ public final class BufferUtil {
}
public static int indexOf(ByteBuf needle, ByteBuf haystack, int startIndex, int endIndex) {
- ByteBuf wrappedHaystack;
- if (startIndex == haystack.readerIndex() && endIndex == haystack.writerIndex()) {
- wrappedHaystack = haystack;
- } else {
- wrappedHaystack = Unpooled.wrappedBuffer(haystack);
- wrappedHaystack.readerIndex(startIndex - haystack.readerIndex());
- wrappedHaystack.writerIndex(endIndex - haystack.readerIndex());
+ int originalReaderIndex = haystack.readerIndex();
+ int originalWriterIndex = haystack.writerIndex();
+ try {
+ haystack.readerIndex(startIndex);
+ haystack.writerIndex(endIndex);
+ return ByteBufUtil.indexOf(needle, haystack);
+ } finally {
+ haystack.readerIndex(originalReaderIndex);
+ haystack.writerIndex(originalWriterIndex);
+ }
+ }
+
+ public static boolean isPrintable(ByteBuf buf, int length) {
+ boolean printable = true;
+ for (int i = 0; i < length; i++) {
+ byte b = buf.getByte(buf.readerIndex() + i);
+ if (b < 32 && b != '\r' && b != '\n') {
+ printable = false;
+ break;
+ }
}
- int result = ByteBufUtil.indexOf(needle, wrappedHaystack);
- return result < 0 ? result : startIndex + result;
+ return printable;
}
}
diff --git a/src/main/java/org/traccar/helper/Checksum.java b/src/main/java/org/traccar/helper/Checksum.java
index 8c3d0063a..db5817275 100644
--- a/src/main/java/org/traccar/helper/Checksum.java
+++ b/src/main/java/org/traccar/helper/Checksum.java
@@ -200,4 +200,19 @@ public final class Checksum {
return (10 - (checksum % 10)) % 10;
}
+ public static int ip(ByteBuffer data) {
+ int sum = 0;
+ while (data.remaining() > 0) {
+ sum += data.get() & 0xff;
+ if ((sum & 0x80000000) > 0) {
+ sum = (sum & 0xffff) + (sum >> 16);
+ }
+ }
+ while ((sum >> 16) > 0) {
+ sum = (sum & 0xffff) + sum >> 16;
+ }
+ sum = (sum == 0xffff) ? sum & 0xffff : (~sum) & 0xffff;
+ return sum;
+ }
+
}
diff --git a/src/main/java/org/traccar/helper/ClassScanner.java b/src/main/java/org/traccar/helper/ClassScanner.java
index c928f6a12..c201d101f 100644
--- a/src/main/java/org/traccar/helper/ClassScanner.java
+++ b/src/main/java/org/traccar/helper/ClassScanner.java
@@ -46,7 +46,7 @@ public final class ClassScanner {
URL packageUrl = baseClass.getClassLoader().getResource(packagePath);
if (packageUrl.getProtocol().equals("jar")) {
- String jarFileName = URLDecoder.decode(packageUrl.getFile(), StandardCharsets.UTF_8.name());
+ String jarFileName = URLDecoder.decode(packageUrl.getFile(), StandardCharsets.UTF_8);
try (JarFile jf = new JarFile(jarFileName.substring(5, jarFileName.indexOf("!")))) {
Enumeration<JarEntry> jarEntries = jf.entries();
while (jarEntries.hasMoreElements()) {
diff --git a/src/main/java/org/traccar/helper/Log.java b/src/main/java/org/traccar/helper/Log.java
index 8c67f9ddc..9aaf1cfd3 100644
--- a/src/main/java/org/traccar/helper/Log.java
+++ b/src/main/java/org/traccar/helper/Log.java
@@ -28,6 +28,10 @@ import java.io.StringWriter;
import java.io.Writer;
import java.net.URL;
import java.nio.charset.StandardCharsets;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.ConsoleHandler;
@@ -51,10 +55,12 @@ public final class Log {
private String suffix;
private Writer writer;
private final boolean rotate;
+ private final String template;
- RollingFileHandler(String name, boolean rotate) {
+ RollingFileHandler(String name, boolean rotate, String rotateInterval) {
this.name = name;
this.rotate = rotate;
+ this.template = rotateInterval.equalsIgnoreCase("HOUR") ? "yyyyMMddHH" : "yyyyMMdd";
}
@Override
@@ -63,7 +69,7 @@ public final class Log {
try {
String suffix = "";
if (rotate) {
- suffix = new SimpleDateFormat("yyyyMMdd").format(new Date(record.getMillis()));
+ suffix = new SimpleDateFormat(template).format(new Date(record.getMillis()));
if (writer != null && !suffix.equals(this.suffix)) {
writer.close();
writer = null;
@@ -165,7 +171,7 @@ public final class Log {
public static void setupDefaultLogger() {
String path = null;
- URL url = ClassLoader.getSystemClassLoader().getResource(".");
+ URL url = ClassLoader.getSystemClassLoader().getResource(".");
if (url != null) {
File jarPath = new File(url.getPath());
File logsPath = new File(jarPath, "logs");
@@ -174,7 +180,7 @@ public final class Log {
}
path = new File(logsPath, "tracker-server.log").getPath();
}
- setupLogger(path == null, path, Level.WARNING.getName(), false, true);
+ setupLogger(path == null, path, Level.WARNING.getName(), false, true, "DAY");
}
public static void setupLogger(Config config) {
@@ -183,11 +189,13 @@ public final class Log {
config.getString(Keys.LOGGER_FILE),
config.getString(Keys.LOGGER_LEVEL),
config.getBoolean(Keys.LOGGER_FULL_STACK_TRACES),
- config.getBoolean(Keys.LOGGER_ROTATE));
+ config.getBoolean(Keys.LOGGER_ROTATE),
+ config.getString(Keys.LOGGER_ROTATE_INTERVAL));
}
private static void setupLogger(
- boolean console, String file, String levelString, boolean fullStackTraces, boolean rotate) {
+ boolean console, String file, String levelString,
+ boolean fullStackTraces, boolean rotate, String rotateInterval) {
Logger rootLogger = Logger.getLogger("");
for (Handler handler : rootLogger.getHandlers()) {
@@ -198,7 +206,7 @@ public final class Log {
if (console) {
handler = new ConsoleHandler();
} else {
- handler = new RollingFileHandler(file, rotate);
+ handler = new RollingFileHandler(file, rotate, rotateInterval);
}
handler.setFormatter(new LogFormatter(fullStackTraces));
@@ -269,4 +277,18 @@ public final class Log {
return s.toString();
}
+ public static long[] getStorageSpace() {
+ long usable = 0;
+ long total = 0;
+ for (Path root : FileSystems.getDefault().getRootDirectories()) {
+ try {
+ FileStore store = Files.getFileStore(root);
+ usable += store.getUsableSpace();
+ total += store.getTotalSpace();
+ } catch (IOException ignored) {
+ }
+ }
+ return new long[]{usable, total};
+ }
+
}
diff --git a/src/main/java/org/traccar/helper/LogAction.java b/src/main/java/org/traccar/helper/LogAction.java
index d16b25483..b255b9206 100644
--- a/src/main/java/org/traccar/helper/LogAction.java
+++ b/src/main/java/org/traccar/helper/LogAction.java
@@ -47,7 +47,7 @@ public final class LogAction {
private static final String PATTERN_OBJECT = "user: %d, action: %s, object: %s, id: %d";
private static final String PATTERN_LINK = "user: %d, action: %s, owner: %s, id: %d, property: %s, id: %d";
- private static final String PATTERN_LOGIN = "user: %d, action: %s";
+ private static final String PATTERN_LOGIN = "user: %d, action: %s, from: %s";
private static final String PATTERN_LOGIN_FAILED = "login failed from: %s";
private static final String PATTERN_DEVICE_ACCUMULATORS = "user: %d, action: %s, deviceId: %d";
private static final String PATTERN_REPORT = "user: %d, report: %s, from: %s, to: %s, devices: %s, groups: %s";
@@ -72,12 +72,12 @@ public final class LogAction {
logLinkAction(ACTION_UNLINK, userId, owner, ownerId, property, propertyId);
}
- public static void login(long userId) {
- logLoginAction(ACTION_LOGIN, userId);
+ public static void login(long userId, String remoteAddress) {
+ logLoginAction(ACTION_LOGIN, userId, remoteAddress);
}
- public static void logout(long userId) {
- logLoginAction(ACTION_LOGOUT, userId);
+ public static void logout(long userId, String remoteAddress) {
+ logLoginAction(ACTION_LOGOUT, userId, remoteAddress);
}
public static void failedLogin(String remoteAddress) {
@@ -105,8 +105,11 @@ public final class LogAction {
Introspector.decapitalize(property.getSimpleName()), propertyId));
}
- private static void logLoginAction(String action, long userId) {
- LOGGER.info(String.format(PATTERN_LOGIN, userId, action));
+ private static void logLoginAction(String action, long userId, String remoteAddress) {
+ if (remoteAddress == null || remoteAddress.isEmpty()) {
+ remoteAddress = "unknown";
+ }
+ LOGGER.info(String.format(PATTERN_LOGIN, userId, action, remoteAddress));
}
public static void logReport(
diff --git a/src/main/java/org/traccar/helper/NetworkUtil.java b/src/main/java/org/traccar/helper/NetworkUtil.java
new file mode 100644
index 000000000..2fe3487da
--- /dev/null
+++ b/src/main/java/org/traccar/helper/NetworkUtil.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+import io.netty.channel.Channel;
+import io.netty.channel.socket.DatagramChannel;
+
+public final class NetworkUtil {
+
+ private NetworkUtil() {
+ }
+
+ public static String session(Channel channel) {
+ char transport = channel instanceof DatagramChannel ? 'U' : 'T';
+ return transport + channel.id().asShortText();
+ }
+
+}
diff --git a/src/main/java/org/traccar/helper/ObdDecoder.java b/src/main/java/org/traccar/helper/ObdDecoder.java
index b22065f4e..3cbae334a 100644
--- a/src/main/java/org/traccar/helper/ObdDecoder.java
+++ b/src/main/java/org/traccar/helper/ObdDecoder.java
@@ -51,22 +51,7 @@ public final class ObdDecoder {
StringBuilder codes = new StringBuilder();
for (int i = 0; i < value.length() / 4; i++) {
int numValue = Integer.parseInt(value.substring(i * 4, (i + 1) * 4), 16);
- codes.append(' ');
- switch (numValue >> 14) {
- case 1:
- codes.append('C');
- break;
- case 2:
- codes.append('B');
- break;
- case 3:
- codes.append('U');
- break;
- default:
- codes.append('P');
- break;
- }
- codes.append(String.format("%04X", numValue & 0x3FFF));
+ codes.append(' ').append(decodeCode(numValue));
}
if (codes.length() > 0) {
return createEntry(Position.KEY_DTCS, codes.toString().trim());
@@ -75,6 +60,25 @@ public final class ObdDecoder {
}
}
+ public static String decodeCode(int value) {
+ char prefix;
+ switch (value >> 14) {
+ case 1:
+ prefix = 'C';
+ break;
+ case 2:
+ prefix = 'B';
+ break;
+ case 3:
+ prefix = 'U';
+ break;
+ default:
+ prefix = 'P';
+ break;
+ }
+ return String.format("%c%04X", prefix, value & 0x3FFF);
+ }
+
public static Map.Entry<String, Object> decodeData(int pid, long value, boolean convert) {
switch (pid) {
case 0x04:
diff --git a/src/main/java/org/traccar/helper/ObjectMapperContextResolver.java b/src/main/java/org/traccar/helper/ObjectMapperContextResolver.java
new file mode 100644
index 000000000..634950b85
--- /dev/null
+++ b/src/main/java/org/traccar/helper/ObjectMapperContextResolver.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.ext.ContextResolver;
+
+// This does not work as a lambda
+public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
+
+ private final ObjectMapper objectMapper;
+
+ @Inject
+ public ObjectMapperContextResolver(ObjectMapper objectMapper) {
+ this.objectMapper = objectMapper;
+ }
+
+ @Override
+ public ObjectMapper getContext(Class<?> clazz) {
+ return objectMapper;
+ }
+
+}
diff --git a/src/main/java/org/traccar/helper/Parser.java b/src/main/java/org/traccar/helper/Parser.java
index 75106e2ba..c2aea28fa 100644
--- a/src/main/java/org/traccar/helper/Parser.java
+++ b/src/main/java/org/traccar/helper/Parser.java
@@ -48,13 +48,25 @@ public class Parser {
}
public boolean hasNext(int number) {
- String value = matcher.group(position);
- if (value != null && !value.isEmpty()) {
- return true;
- } else {
- position += number;
- return false;
+ for (int i = position; i < position + number; i++) {
+ String value = matcher.group(i);
+ if (value == null || value.isEmpty()) {
+ position += number;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean hasNextAny(int number) {
+ for (int i = position; i < position + number; i++) {
+ String value = matcher.group(i);
+ if (value != null && !value.isEmpty()) {
+ return true;
+ }
}
+ position += number;
+ return false;
}
public String next() {
@@ -155,6 +167,7 @@ public class Parser {
public enum CoordinateFormat {
DEG_DEG,
+ DEG_DEG_HEM,
DEG_HEM,
DEG_MIN_MIN,
DEG_MIN_HEM,
@@ -173,6 +186,10 @@ public class Parser {
case DEG_DEG:
coordinate = Double.parseDouble(next() + '.' + next());
break;
+ case DEG_DEG_HEM:
+ coordinate = Double.parseDouble(next() + '.' + next());
+ hemisphere = next();
+ break;
case DEG_HEM:
coordinate = nextDouble(0);
hemisphere = next();
diff --git a/src/main/java/org/traccar/helper/PatternUtil.java b/src/main/java/org/traccar/helper/PatternUtil.java
index 74813e1d9..a46c7b7b4 100644
--- a/src/main/java/org/traccar/helper/PatternUtil.java
+++ b/src/main/java/org/traccar/helper/PatternUtil.java
@@ -63,7 +63,7 @@ public final class PatternUtil {
for (int i = 0; i < pattern.length(); i++) {
try {
- Matcher matcher = Pattern.compile("(" + pattern.substring(0, i) + ").*").matcher(input);
+ Matcher matcher = Pattern.compile("(" + pattern.substring(0, i) + ")[\\s\\S]*").matcher(input);
if (matcher.matches()) {
result.patternMatch = pattern.substring(0, i);
result.patternTail = pattern.substring(i);
diff --git a/src/main/java/org/traccar/helper/StringUtil.java b/src/main/java/org/traccar/helper/StringUtil.java
new file mode 100644
index 000000000..9b4d717f4
--- /dev/null
+++ b/src/main/java/org/traccar/helper/StringUtil.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.helper;
+
+public final class StringUtil {
+
+ private StringUtil() {
+ }
+
+ public static boolean containsHex(String value) {
+ for (char c : value.toCharArray()) {
+ if (c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/src/main/java/org/traccar/helper/ServletHelper.java b/src/main/java/org/traccar/helper/WebHelper.java
index b6c587ec3..9533fe84b 100644
--- a/src/main/java/org/traccar/helper/ServletHelper.java
+++ b/src/main/java/org/traccar/helper/WebHelper.java
@@ -15,11 +15,18 @@
*/
package org.traccar.helper;
-import javax.servlet.http.HttpServletRequest;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
-public final class ServletHelper {
+import jakarta.servlet.http.HttpServletRequest;
- private ServletHelper() {
+import org.eclipse.jetty.util.URIUtil;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+public final class WebHelper {
+
+ private WebHelper() {
}
public static String retrieveRemoteAddress(HttpServletRequest request) {
@@ -42,4 +49,17 @@ public final class ServletHelper {
}
}
+ public static String retrieveWebUrl(Config config) {
+ if (config.hasKey(Keys.WEB_URL)) {
+ return config.getString(Keys.WEB_URL).replaceAll("/$", "");
+ } else {
+ String address;
+ try {
+ address = config.getString(Keys.WEB_ADDRESS, InetAddress.getLocalHost().getHostAddress());
+ } catch (UnknownHostException e) {
+ address = "localhost";
+ }
+ return URIUtil.newURI("http", address, config.getInteger(Keys.WEB_PORT), "", "");
+ }
+ }
}
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..2630f64f0
--- /dev/null
+++ b/src/main/java/org/traccar/helper/model/AttributeUtil.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2022 - 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.helper.model;
+
+import org.traccar.api.security.PermissionsService;
+import org.traccar.config.Config;
+import org.traccar.config.ConfigKey;
+import org.traccar.config.KeyType;
+import org.traccar.config.Keys;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.model.Server;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+public final class AttributeUtil {
+
+ private AttributeUtil() {
+ }
+
+ public interface Provider {
+ Device getDevice();
+ Group getGroup(long groupId);
+ Server getServer();
+ Config getConfig();
+ }
+
+ public static <T> T lookup(CacheManager cacheManager, ConfigKey<T> key, long deviceId) {
+ return lookup(new CacheProvider(cacheManager, deviceId), key);
+ }
+
+ @SuppressWarnings({ "deprecation", "unchecked" })
+ public static <T> T lookup(Provider provider, ConfigKey<T> key) {
+ Device device = provider.getDevice();
+ Object result = device.getAttributes().get(key.getKey());
+ long groupId = device.getGroupId();
+ while (result == null && groupId > 0) {
+ Group group = provider.getGroup(groupId);
+ if (group != null) {
+ result = group.getAttributes().get(key.getKey());
+ groupId = group.getGroupId();
+ } else {
+ groupId = 0;
+ }
+ }
+ if (result == null && key.hasType(KeyType.SERVER)) {
+ result = provider.getServer().getAttributes().get(key.getKey());
+ }
+ if (result == null && key.hasType(KeyType.CONFIG)) {
+ result = provider.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();
+ }
+
+ public static String getDevicePassword(
+ CacheManager cacheManager, long deviceId, String protocol, String defaultPassword) {
+
+ String password = lookup(cacheManager, Keys.DEVICE_PASSWORD, deviceId);
+ if (password != null) {
+ return password;
+ }
+
+ if (protocol != null) {
+ password = cacheManager.getConfig().getString(Keys.PROTOCOL_DEVICE_PASSWORD.withPrefix(protocol));
+ if (password != null) {
+ return password;
+ }
+ }
+
+ return defaultPassword;
+ }
+
+ public static class CacheProvider implements Provider {
+
+ private final CacheManager cacheManager;
+ private final long deviceId;
+
+ public CacheProvider(CacheManager cacheManager, long deviceId) {
+ this.cacheManager = cacheManager;
+ this.deviceId = deviceId;
+ }
+
+ @Override
+ public Device getDevice() {
+ return cacheManager.getObject(Device.class, deviceId);
+ }
+
+ @Override
+ public Group getGroup(long groupId) {
+ return cacheManager.getObject(Group.class, groupId);
+ }
+
+ @Override
+ public Server getServer() {
+ return cacheManager.getServer();
+ }
+
+ @Override
+ public Config getConfig() {
+ return cacheManager.getConfig();
+ }
+ }
+
+ public static class StorageProvider implements Provider {
+
+ private final Config config;
+ private final Storage storage;
+ private final PermissionsService permissionsService;
+ private final Device device;
+
+ public StorageProvider(Config config, Storage storage, PermissionsService permissionsService, Device device) {
+ this.config = config;
+ this.storage = storage;
+ this.permissionsService = permissionsService;
+ this.device = device;
+ }
+
+ @Override
+ public Device getDevice() {
+ return device;
+ }
+
+ @Override
+ public Group getGroup(long groupId) {
+ try {
+ return storage.getObject(
+ Group.class, new Request(new Columns.All(), new Condition.Equals("id", groupId)));
+ } catch (StorageException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public Server getServer() {
+ try {
+ return permissionsService.getServer();
+ } catch (StorageException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public Config getConfig() {
+ return config;
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/helper/model/DeviceUtil.java b/src/main/java/org/traccar/helper/model/DeviceUtil.java
new file mode 100644
index 000000000..5d8cb5f25
--- /dev/null
+++ b/src/main/java/org/traccar/helper/model/DeviceUtil.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2022 - 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.helper.model;
+
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.model.User;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public final class DeviceUtil {
+
+ private DeviceUtil() {
+ }
+
+ public static void resetStatus(Storage storage) throws StorageException {
+ storage.updateObject(new Device(), new Request(new Columns.Include("status")));
+ }
+
+
+ public static Collection<Device> getAccessibleDevices(
+ Storage storage, long userId,
+ Collection<Long> deviceIds, Collection<Long> groupIds) throws StorageException {
+
+ var devices = storage.getObjects(Device.class, new Request(
+ new Columns.All(),
+ new Condition.Permission(User.class, userId, Device.class)));
+ var deviceById = devices.stream()
+ .collect(Collectors.toUnmodifiableMap(Device::getId, x -> x));
+ var devicesByGroup = devices.stream()
+ .filter(x -> x.getGroupId() > 0)
+ .collect(Collectors.groupingBy(Device::getGroupId));
+
+ var groups = storage.getObjects(Group.class, new Request(
+ new Columns.All(),
+ new Condition.Permission(User.class, userId, Group.class)));
+ var groupsByGroup = groups.stream()
+ .filter(x -> x.getGroupId() > 0)
+ .collect(Collectors.groupingBy(Group::getGroupId));
+
+ var results = deviceIds.stream()
+ .map(deviceById::get)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet());
+
+ var groupQueue = new LinkedList<>(groupIds);
+ while (!groupQueue.isEmpty()) {
+ long groupId = groupQueue.pop();
+ results.addAll(devicesByGroup.getOrDefault(groupId, Collections.emptyList()));
+ groupQueue.addAll(groupsByGroup.getOrDefault(groupId, Collections.emptyList())
+ .stream().map(Group::getId).collect(Collectors.toUnmodifiableList()));
+ }
+
+ return results;
+ }
+
+}
diff --git a/src/main/java/org/traccar/helper/model/GeofenceUtil.java b/src/main/java/org/traccar/helper/model/GeofenceUtil.java
new file mode 100644
index 000000000..9f063a8b4
--- /dev/null
+++ b/src/main/java/org/traccar/helper/model/GeofenceUtil.java
@@ -0,0 +1,42 @@
+/*
+ * 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.Config;
+import org.traccar.model.Geofence;
+import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class GeofenceUtil {
+
+ private GeofenceUtil() {
+ }
+
+ public static List<Long> getCurrentGeofences(Config config, CacheManager cacheManager, Position position) {
+ List<Long> result = new ArrayList<>();
+ for (Geofence geofence : cacheManager.getDeviceObjects(position.getDeviceId(), Geofence.class)) {
+ if (geofence.getGeometry().containsPoint(
+ config, geofence, position.getLatitude(), position.getLongitude())) {
+ result.add(geofence.getId());
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/src/main/java/org/traccar/helper/model/PositionUtil.java b/src/main/java/org/traccar/helper/model/PositionUtil.java
new file mode 100644
index 000000000..6c380b81a
--- /dev/null
+++ b/src/main/java/org/traccar/helper/model/PositionUtil.java
@@ -0,0 +1,80 @@
+/*
+ * 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.model.BaseModel;
+import org.traccar.model.Device;
+import org.traccar.model.Position;
+import org.traccar.model.User;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Order;
+import org.traccar.storage.query.Request;
+
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public final class PositionUtil {
+
+ private PositionUtil() {
+ }
+
+ public static boolean isLatest(CacheManager cacheManager, Position position) {
+ Position lastPosition = cacheManager.getPosition(position.getDeviceId());
+ return lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) >= 0;
+ }
+
+ public static double calculateDistance(Position first, Position last, boolean useOdometer) {
+ double distance;
+ double firstOdometer = first.getDouble(Position.KEY_ODOMETER);
+ double lastOdometer = last.getDouble(Position.KEY_ODOMETER);
+
+ if (useOdometer && firstOdometer != 0.0 && lastOdometer != 0.0) {
+ distance = lastOdometer - firstOdometer;
+ } else {
+ distance = last.getDouble(Position.KEY_TOTAL_DISTANCE) - first.getDouble(Position.KEY_TOTAL_DISTANCE);
+ }
+ return distance;
+ }
+
+ public static List<Position> getPositions(
+ Storage storage, long deviceId, Date from, Date to) throws StorageException {
+ return storage.getObjects(Position.class, new Request(
+ new Columns.All(),
+ new Condition.And(
+ new Condition.Equals("deviceId", deviceId),
+ new Condition.Between("fixTime", "from", from, "to", to)),
+ new Order("fixTime")));
+ }
+
+ public static List<Position> getLatestPositions(Storage storage, long userId) throws StorageException {
+ var devices = storage.getObjects(Device.class, new Request(
+ new Columns.Include("id"),
+ new Condition.Permission(User.class, userId, Device.class)));
+ var deviceIds = devices.stream().map(BaseModel::getId).collect(Collectors.toUnmodifiableSet());
+
+ var positions = storage.getObjects(Position.class, new Request(
+ new Columns.All(), new Condition.LatestPositions()));
+ return positions.stream()
+ .filter(position -> deviceIds.contains(position.getDeviceId()))
+ .collect(Collectors.toList());
+ }
+
+}
diff --git a/src/main/java/org/traccar/helper/model/UserUtil.java b/src/main/java/org/traccar/helper/model/UserUtil.java
new file mode 100644
index 000000000..4b1c404f9
--- /dev/null
+++ b/src/main/java/org/traccar/helper/model/UserUtil.java
@@ -0,0 +1,78 @@
+/*
+ * 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.Config;
+import org.traccar.config.Keys;
+import org.traccar.model.Server;
+import org.traccar.model.User;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Order;
+import org.traccar.storage.query.Request;
+
+import java.util.Date;
+import java.util.TimeZone;
+
+public final class UserUtil {
+
+ private UserUtil() {
+ }
+
+ public static boolean isEmpty(Storage storage) throws StorageException {
+ return storage.getObjects(User.class, new Request(
+ new Columns.Include("id"),
+ new Order("id", false, 1))).isEmpty();
+ }
+
+ public static String getDistanceUnit(Server server, User user) {
+ return lookupStringAttribute(server, user, "distanceUnit", "km");
+ }
+
+ public static String getSpeedUnit(Server server, User user) {
+ return lookupStringAttribute(server, user, "speedUnit", "kn");
+ }
+
+ public static String getVolumeUnit(Server server, User user) {
+ return lookupStringAttribute(server, user, "volumeUnit", "ltr");
+ }
+
+ public static TimeZone getTimezone(Server server, User user) {
+ String timezone = lookupStringAttribute(server, user, "timezone", null);
+ return timezone != null ? TimeZone.getTimeZone(timezone) : TimeZone.getDefault();
+ }
+
+ private static String lookupStringAttribute(Server server, User user, String key, String defaultValue) {
+ String preference;
+ String serverPreference = server.getString(key);
+ String userPreference = user.getString(key);
+ if (server.getForceSettings()) {
+ preference = serverPreference != null ? serverPreference : userPreference;
+ } else {
+ preference = userPreference != null ? userPreference : serverPreference;
+ }
+ return preference != null ? preference : defaultValue;
+ }
+
+ public static void setUserDefaults(User user, Config config) {
+ user.setDeviceLimit(config.getInteger(Keys.USERS_DEFAULT_DEVICE_LIMIT));
+ int expirationDays = config.getInteger(Keys.USERS_DEFAULT_EXPIRATION_DAYS);
+ if (expirationDays > 0) {
+ user.setExpirationTime(new Date(System.currentTimeMillis() + expirationDays * 86400000L));
+ }
+ }
+}
diff --git a/src/main/java/org/traccar/mail/LogMailManager.java b/src/main/java/org/traccar/mail/LogMailManager.java
new file mode 100644
index 000000000..90de3bcce
--- /dev/null
+++ b/src/main/java/org/traccar/mail/LogMailManager.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2022 - 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.mail;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.model.User;
+
+import jakarta.mail.MessagingException;
+import jakarta.mail.internet.MimeBodyPart;
+
+public class LogMailManager implements MailManager {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(LogMailManager.class);
+
+ @Override
+ public boolean getEmailEnabled() {
+ return true;
+ }
+
+ @Override
+ public void sendMessage(
+ User user, boolean system, String subject, String body) throws MessagingException {
+ sendMessage(user, system, subject, body, null);
+ }
+
+ @Override
+ public void sendMessage(
+ User user, boolean system, String subject, String body, MimeBodyPart attachment) throws MessagingException {
+ LOGGER.info(
+ "Email sent\nTo: {}\nSubject: {}\nAttachment: {}\nBody:\n{}",
+ user.getEmail(), subject, attachment != null ? attachment.getFileName() : null, body);
+ }
+
+}
diff --git a/src/main/java/org/traccar/mail/MailManager.java b/src/main/java/org/traccar/mail/MailManager.java
new file mode 100644
index 000000000..d05a07de9
--- /dev/null
+++ b/src/main/java/org/traccar/mail/MailManager.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022 - 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.mail;
+
+import org.traccar.model.User;
+
+import jakarta.mail.MessagingException;
+import jakarta.mail.internet.MimeBodyPart;
+
+public interface MailManager {
+
+ boolean getEmailEnabled();
+
+ void sendMessage(
+ User user, boolean system, String subject, String body) throws MessagingException;
+
+ void sendMessage(
+ User user, boolean system, String subject, String body, MimeBodyPart attachment) throws MessagingException;
+
+}
diff --git a/src/main/java/org/traccar/mail/SmtpMailManager.java b/src/main/java/org/traccar/mail/SmtpMailManager.java
new file mode 100644
index 000000000..70099d879
--- /dev/null
+++ b/src/main/java/org/traccar/mail/SmtpMailManager.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@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.mail;
+
+import org.traccar.config.Config;
+import org.traccar.config.ConfigKey;
+import org.traccar.config.Keys;
+import org.traccar.database.StatisticsManager;
+import org.traccar.model.User;
+import org.traccar.notification.PropertiesProvider;
+
+import jakarta.mail.BodyPart;
+import jakarta.mail.Message;
+import jakarta.mail.MessagingException;
+import jakarta.mail.Multipart;
+import jakarta.mail.Session;
+import jakarta.mail.Transport;
+import jakarta.mail.internet.InternetAddress;
+import jakarta.mail.internet.MimeBodyPart;
+import jakarta.mail.internet.MimeMessage;
+import jakarta.mail.internet.MimeMultipart;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+import java.util.Properties;
+
+public final class SmtpMailManager implements MailManager {
+
+ private static final String CONTENT_TYPE = "text/html; charset=utf-8";
+
+ private final Config config;
+ private final StatisticsManager statisticsManager;
+
+ public SmtpMailManager(Config config, StatisticsManager statisticsManager) {
+ this.config = config;
+ this.statisticsManager = statisticsManager;
+ }
+
+ private static void copyBooleanProperty(
+ Properties properties, PropertiesProvider provider, ConfigKey<Boolean> key) {
+ Boolean value = provider.getBoolean(key);
+ if (value != null) {
+ properties.put(key.getKey(), String.valueOf(value));
+ }
+ }
+
+ private static void copyStringProperty(
+ Properties properties, PropertiesProvider provider, ConfigKey<String> key) {
+ String value = provider.getString(key);
+ if (value != null) {
+ properties.put(key.getKey(), value);
+ }
+ }
+
+ private static Properties getProperties(PropertiesProvider provider) {
+ String host = provider.getString(Keys.MAIL_SMTP_HOST);
+ if (host != null) {
+ Properties properties = new Properties();
+
+ properties.put(Keys.MAIL_TRANSPORT_PROTOCOL.getKey(), provider.getString(Keys.MAIL_TRANSPORT_PROTOCOL));
+ properties.put(Keys.MAIL_SMTP_HOST.getKey(), host);
+ properties.put(Keys.MAIL_SMTP_PORT.getKey(), String.valueOf(provider.getInteger(Keys.MAIL_SMTP_PORT)));
+
+ copyBooleanProperty(properties, provider, Keys.MAIL_SMTP_STARTTLS_ENABLE);
+ copyBooleanProperty(properties, provider, Keys.MAIL_SMTP_STARTTLS_REQUIRED);
+ copyBooleanProperty(properties, provider, Keys.MAIL_SMTP_SSL_ENABLE);
+ copyStringProperty(properties, provider, Keys.MAIL_SMTP_SSL_TRUST);
+ copyStringProperty(properties, provider, Keys.MAIL_SMTP_SSL_PROTOCOLS);
+ copyStringProperty(properties, provider, Keys.MAIL_SMTP_USERNAME);
+ copyStringProperty(properties, provider, Keys.MAIL_SMTP_PASSWORD);
+ copyStringProperty(properties, provider, Keys.MAIL_SMTP_FROM);
+ copyStringProperty(properties, provider, Keys.MAIL_SMTP_FROM_NAME);
+
+ return properties;
+ }
+ return null;
+ }
+
+ public boolean getEmailEnabled() {
+ return config.hasKey(Keys.MAIL_SMTP_HOST);
+ }
+
+ @Override
+ public void sendMessage(
+ User user, boolean system, String subject, String body) throws MessagingException {
+ sendMessage(user, system, subject, body, null);
+ }
+
+ @Override
+ public void sendMessage(
+ User user, boolean system, String subject, String body, MimeBodyPart attachment) throws MessagingException {
+
+ Properties properties = null;
+ if (!config.getBoolean(Keys.MAIL_SMTP_IGNORE_USER_CONFIG)) {
+ properties = getProperties(new PropertiesProvider(user));
+ }
+ if (properties == null && (system || !config.getBoolean(Keys.MAIL_SMTP_SYSTEM_ONLY))) {
+ properties = getProperties(new PropertiesProvider(config));
+ }
+ if (properties == null) {
+ throw new MessagingException("No SMTP configuration found");
+ }
+
+ Session session = Session.getInstance(properties);
+
+ MimeMessage message = new MimeMessage(session);
+
+ String from = properties.getProperty(Keys.MAIL_SMTP_FROM.getKey());
+ if (from != null) {
+ String fromName = properties.getProperty(Keys.MAIL_SMTP_FROM_NAME.getKey());
+ if (fromName != null) {
+ try {
+ message.setFrom(new InternetAddress(from, fromName));
+ } catch (UnsupportedEncodingException e) {
+ throw new MessagingException("Email address issue");
+ }
+ } else {
+ message.setFrom(new InternetAddress(from));
+ }
+ }
+
+ message.addRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail()));
+ message.setSubject(subject);
+ message.setSentDate(new Date());
+
+ if (attachment != null) {
+ Multipart multipart = new MimeMultipart();
+
+ BodyPart messageBodyPart = new MimeBodyPart();
+ messageBodyPart.setContent(body, CONTENT_TYPE);
+ multipart.addBodyPart(messageBodyPart);
+ multipart.addBodyPart(attachment);
+
+ message.setContent(multipart);
+ } else {
+ message.setContent(body, CONTENT_TYPE);
+ }
+
+ try (Transport transport = session.getTransport()) {
+ statisticsManager.registerMail();
+ transport.connect(
+ properties.getProperty(Keys.MAIL_SMTP_HOST.getKey()),
+ properties.getProperty(Keys.MAIL_SMTP_USERNAME.getKey()),
+ properties.getProperty(Keys.MAIL_SMTP_PASSWORD.getKey()));
+ transport.sendMessage(message, message.getAllRecipients());
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/database/CalendarManager.java b/src/main/java/org/traccar/model/BaseCommand.java
index 44ced1082..f87b8ef65 100644
--- a/src/main/java/org/traccar/database/CalendarManager.java
+++ b/src/main/java/org/traccar/model/BaseCommand.java
@@ -1,6 +1,5 @@
/*
- * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org)
+ * 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.
@@ -14,14 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.database;
+package org.traccar.model;
-import org.traccar.model.Calendar;
+public class BaseCommand extends Message {
-public class CalendarManager extends SimpleObjectManager<Calendar> {
+ private boolean textChannel;
- public CalendarManager(DataManager dataManager) {
- super(dataManager, Calendar.class);
+ public boolean getTextChannel() {
+ return textChannel;
+ }
+
+ public void setTextChannel(boolean textChannel) {
+ this.textChannel = textChannel;
}
}
diff --git a/src/main/java/org/traccar/model/BaseModel.java b/src/main/java/org/traccar/model/BaseModel.java
index 8bdb916e8..acde0f83d 100644
--- a/src/main/java/org/traccar/model/BaseModel.java
+++ b/src/main/java/org/traccar/model/BaseModel.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,11 +20,11 @@ public class BaseModel {
private long id;
- public final long getId() {
+ public long getId() {
return id;
}
- public final void setId(long id) {
+ public void setId(long id) {
this.id = id;
}
diff --git a/src/main/java/org/traccar/model/Calendar.java b/src/main/java/org/traccar/model/Calendar.java
index 102c0be52..03f1995ba 100644
--- a/src/main/java/org/traccar/model/Calendar.java
+++ b/src/main/java/org/traccar/model/Calendar.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,6 +24,7 @@ import net.fortuna.ical4j.filter.predicate.PeriodRule;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Period;
import net.fortuna.ical4j.model.component.CalendarComponent;
+import net.fortuna.ical4j.model.component.VEvent;
import org.traccar.storage.QueryIgnore;
import org.traccar.storage.StorageName;
@@ -32,6 +33,8 @@ import java.io.IOException;
import java.time.Duration;
import java.util.Collection;
import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
@StorageName("tc_calendars")
public class Calendar extends ExtendedModel {
@@ -49,13 +52,13 @@ public class Calendar extends ExtendedModel {
private byte[] data;
public byte[] getData() {
- return data.clone();
+ return data;
}
public void setData(byte[] data) throws IOException, ParserException {
CalendarBuilder builder = new CalendarBuilder();
calendar = builder.build(new ByteArrayInputStream(data));
- this.data = data.clone();
+ this.data = data;
}
private net.fortuna.ical4j.model.Calendar calendar;
@@ -66,14 +69,24 @@ public class Calendar extends ExtendedModel {
return calendar;
}
- public boolean checkMoment(Date date) {
+ private Collection<VEvent> findEvents(Date date) {
if (calendar != null) {
- Period period = new Period(new DateTime(date), Duration.ZERO);
- Filter<CalendarComponent> filter = new Filter<>(new PeriodRule<>(period));
- Collection<CalendarComponent> events = filter.filter(calendar.getComponents(CalendarComponent.VEVENT));
- return events != null && !events.isEmpty();
+ var filter = new Filter<VEvent>(new PeriodRule<>(new Period(new DateTime(date), Duration.ZERO)));
+ return filter.filter(calendar.getComponents(CalendarComponent.VEVENT));
+ } else {
+ return List.of();
}
- return false;
+ }
+
+ public Collection<Period> findPeriods(Date date) {
+ var calendarDate = new net.fortuna.ical4j.model.Date(date);
+ return findEvents(date).stream()
+ .flatMap((event) -> event.getConsumedTime(calendarDate, calendarDate).stream())
+ .collect(Collectors.toSet());
+ }
+
+ public boolean checkMoment(Date date) {
+ return !findEvents(date).isEmpty();
}
}
diff --git a/src/main/java/org/traccar/model/CellTower.java b/src/main/java/org/traccar/model/CellTower.java
index 254487471..355594c64 100644
--- a/src/main/java/org/traccar/model/CellTower.java
+++ b/src/main/java/org/traccar/model/CellTower.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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.
@@ -16,9 +16,11 @@
package org.traccar.model;
import com.fasterxml.jackson.annotation.JsonInclude;
-import org.traccar.Context;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
+import java.util.Objects;
+
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CellTower {
@@ -37,14 +39,12 @@ public class CellTower {
return cellTower;
}
- public static CellTower fromLacCid(int lac, long cid) {
- return from(
- Context.getConfig().getInteger(Keys.GEOLOCATION_MCC),
- Context.getConfig().getInteger(Keys.GEOLOCATION_MCC), lac, cid);
+ public static CellTower fromLacCid(Config config, int lac, long cid) {
+ return from(config.getInteger(Keys.GEOLOCATION_MCC), config.getInteger(Keys.GEOLOCATION_MNC), lac, cid);
}
- public static CellTower fromCidLac(long cid, int lac) {
- return fromLacCid(lac, cid);
+ public static CellTower fromCidLac(Config config, long cid, int lac) {
+ return fromLacCid(config, lac, cid);
}
private String radioType;
@@ -113,4 +113,26 @@ public class CellTower {
mobileNetworkCode = Integer.parseInt(operatorString.substring(3));
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CellTower cellTower = (CellTower) o;
+ return Objects.equals(radioType, cellTower.radioType)
+ && Objects.equals(cellId, cellTower.cellId)
+ && Objects.equals(locationAreaCode, cellTower.locationAreaCode)
+ && Objects.equals(mobileCountryCode, cellTower.mobileCountryCode)
+ && Objects.equals(mobileNetworkCode, cellTower.mobileNetworkCode)
+ && Objects.equals(signalStrength, cellTower.signalStrength);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(radioType, cellId, locationAreaCode, mobileCountryCode, mobileNetworkCode, signalStrength);
+ }
+
}
diff --git a/src/main/java/org/traccar/model/Command.java b/src/main/java/org/traccar/model/Command.java
index 03961c7b2..99988dd82 100644
--- a/src/main/java/org/traccar/model/Command.java
+++ b/src/main/java/org/traccar/model/Command.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -22,7 +22,7 @@ import org.traccar.storage.StorageName;
@StorageName("tc_commands")
@JsonIgnoreProperties(ignoreUnknown = true)
-public class Command extends Message implements Cloneable {
+public class Command extends BaseCommand {
public static final String TYPE_CUSTOM = "custom";
public static final String TYPE_IDENTIFICATION = "deviceIdentification";
@@ -58,11 +58,10 @@ public class Command extends Message implements Cloneable {
public static final String TYPE_GET_MODEM_STATUS = "getModemStatus";
public static final String TYPE_GET_DEVICE_STATUS = "getDeviceStatus";
public static final String TYPE_SET_SPEED_LIMIT = "setSpeedLimit";
-
public static final String TYPE_MODE_POWER_SAVING = "modePowerSaving";
public static final String TYPE_MODE_DEEP_SLEEP = "modeDeepSleep";
- public static final String TYPE_ALARM_GEOFENCE = "movementAlarm";
+ public static final String TYPE_ALARM_GEOFENCE = "alarmGeofence";
public static final String TYPE_ALARM_BATTERY = "alarmBattery";
public static final String TYPE_ALARM_SOS = "alarmSos";
public static final String TYPE_ALARM_REMOVE = "alarmRemove";
@@ -85,21 +84,6 @@ public class Command extends Message implements Cloneable {
public static final String KEY_SERVER = "server";
public static final String KEY_PORT = "port";
- @Override
- public Command clone() throws CloneNotSupportedException {
- return (Command) super.clone();
- }
-
- private boolean textChannel;
-
- public boolean getTextChannel() {
- return textChannel;
- }
-
- public void setTextChannel(boolean textChannel) {
- this.textChannel = textChannel;
- }
-
@QueryIgnore
@Override
public long getDeviceId() {
diff --git a/src/main/java/org/traccar/model/Device.java b/src/main/java/org/traccar/model/Device.java
index 219f078ed..e07815976 100644
--- a/src/main/java/org/traccar/model/Device.java
+++ b/src/main/java/org/traccar/model/Device.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,15 +15,26 @@
*/
package org.traccar.model;
-import java.util.Date;
-import java.util.List;
-
-import org.traccar.storage.QueryExtended;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import org.traccar.storage.QueryIgnore;
import org.traccar.storage.StorageName;
+import java.util.Date;
+
@StorageName("tc_devices")
-public class Device extends GroupedModel {
+public class Device extends GroupedModel implements Disableable, Schedulable {
+
+ private long calendarId;
+
+ @Override
+ public long getCalendarId() {
+ return calendarId;
+ }
+
+ @Override
+ public void setCalendarId(long calendarId) {
+ this.calendarId = calendarId;
+ }
private String name;
@@ -42,7 +53,7 @@ public class Device extends GroupedModel {
}
public void setUniqueId(String uniqueId) {
- this.uniqueId = uniqueId;
+ this.uniqueId = uniqueId.trim();
}
public static final String STATUS_UNKNOWN = "unknown";
@@ -56,18 +67,17 @@ public class Device extends GroupedModel {
return status != null ? status : STATUS_OFFLINE;
}
- @QueryIgnore
public void setStatus(String status) {
- this.status = status;
+ this.status = status != null ? status.trim() : null;
}
private Date lastUpdate;
+ @QueryIgnore
public Date getLastUpdate() {
return this.lastUpdate;
}
- @QueryExtended
public void setLastUpdate(Date lastUpdate) {
this.lastUpdate = lastUpdate;
}
@@ -79,23 +89,10 @@ public class Device extends GroupedModel {
return positionId;
}
- @QueryIgnore
public void setPositionId(long positionId) {
this.positionId = positionId;
}
- private List<Long> geofenceIds;
-
- @QueryIgnore
- public List<Long> getGeofenceIds() {
- return geofenceIds;
- }
-
- @QueryIgnore
- public void setGeofenceIds(List<Long> geofenceIds) {
- this.geofenceIds = geofenceIds;
- }
-
private String phone;
public String getPhone() {
@@ -103,7 +100,7 @@ public class Device extends GroupedModel {
}
public void setPhone(String phone) {
- this.phone = phone;
+ this.phone = phone != null ? phone.trim() : null;
}
private String model;
@@ -138,12 +135,117 @@ public class Device extends GroupedModel {
private boolean disabled;
+ @Override
public boolean getDisabled() {
return disabled;
}
+ @Override
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
+ private Date expirationTime;
+
+ @Override
+ public Date getExpirationTime() {
+ return expirationTime;
+ }
+
+ @Override
+ public void setExpirationTime(Date expirationTime) {
+ this.expirationTime = expirationTime;
+ }
+
+ private boolean motionStreak;
+
+ @QueryIgnore
+ @JsonIgnore
+ public boolean getMotionStreak() {
+ return motionStreak;
+ }
+
+ @JsonIgnore
+ public void setMotionStreak(boolean motionStreak) {
+ this.motionStreak = motionStreak;
+ }
+
+ private boolean motionState;
+
+ @QueryIgnore
+ @JsonIgnore
+ public boolean getMotionState() {
+ return motionState;
+ }
+
+ @JsonIgnore
+ public void setMotionState(boolean motionState) {
+ this.motionState = motionState;
+ }
+
+ private Date motionTime;
+
+ @QueryIgnore
+ @JsonIgnore
+ public Date getMotionTime() {
+ return motionTime;
+ }
+
+ @JsonIgnore
+ public void setMotionTime(Date motionTime) {
+ this.motionTime = motionTime;
+ }
+
+ private double motionDistance;
+
+ @QueryIgnore
+ @JsonIgnore
+ public double getMotionDistance() {
+ return motionDistance;
+ }
+
+ @JsonIgnore
+ public void setMotionDistance(double motionDistance) {
+ this.motionDistance = motionDistance;
+ }
+
+ private boolean overspeedState;
+
+ @QueryIgnore
+ @JsonIgnore
+ public boolean getOverspeedState() {
+ return overspeedState;
+ }
+
+ @JsonIgnore
+ public void setOverspeedState(boolean overspeedState) {
+ this.overspeedState = overspeedState;
+ }
+
+ private Date overspeedTime;
+
+ @QueryIgnore
+ @JsonIgnore
+ public Date getOverspeedTime() {
+ return overspeedTime;
+ }
+
+ @JsonIgnore
+ public void setOverspeedTime(Date overspeedTime) {
+ this.overspeedTime = overspeedTime;
+ }
+
+ private long overspeedGeofenceId;
+
+ @QueryIgnore
+ @JsonIgnore
+ public long getOverspeedGeofenceId() {
+ return overspeedGeofenceId;
+ }
+
+ @JsonIgnore
+ public void setOverspeedGeofenceId(long overspeedGeofenceId) {
+ this.overspeedGeofenceId = overspeedGeofenceId;
+ }
+
}
diff --git a/src/main/java/org/traccar/model/DeviceState.java b/src/main/java/org/traccar/model/DeviceState.java
deleted file mode 100644
index 75d6726ee..000000000
--- a/src/main/java/org/traccar/model/DeviceState.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.model;
-
-public class DeviceState {
-
- private Boolean motionState;
-
- public void setMotionState(boolean motionState) {
- this.motionState = motionState;
- }
-
- public Boolean getMotionState() {
- return motionState;
- }
-
- private Position motionPosition;
-
- public void setMotionPosition(Position motionPosition) {
- this.motionPosition = motionPosition;
- }
-
- public Position getMotionPosition() {
- return motionPosition;
- }
-
- private Boolean overspeedState;
-
- public void setOverspeedState(boolean overspeedState) {
- this.overspeedState = overspeedState;
- }
-
- public Boolean getOverspeedState() {
- return overspeedState;
- }
-
- private Position overspeedPosition;
-
- public void setOverspeedPosition(Position overspeedPosition) {
- this.overspeedPosition = overspeedPosition;
- }
-
- public Position getOverspeedPosition() {
- return overspeedPosition;
- }
-
- private long overspeedGeofenceId;
-
- public void setOverspeedGeofenceId(long overspeedGeofenceId) {
- this.overspeedGeofenceId = overspeedGeofenceId;
- }
-
- public long getOverspeedGeofenceId() {
- return overspeedGeofenceId;
- }
-
-}
diff --git a/src/main/java/org/traccar/model/Disableable.java b/src/main/java/org/traccar/model/Disableable.java
new file mode 100644
index 000000000..1145d6279
--- /dev/null
+++ b/src/main/java/org/traccar/model/Disableable.java
@@ -0,0 +1,39 @@
+/*
+ * 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.model;
+
+import java.util.Date;
+
+public interface Disableable {
+
+ boolean getDisabled();
+
+ void setDisabled(boolean disabled);
+
+ Date getExpirationTime();
+
+ void setExpirationTime(Date expirationTime);
+
+ default void checkDisabled() throws SecurityException {
+ if (getDisabled()) {
+ throw new SecurityException(getClass().getSimpleName() + " is disabled");
+ }
+ if (getExpirationTime() != null && System.currentTimeMillis() > getExpirationTime().getTime()) {
+ throw new SecurityException(getClass().getSimpleName() + " has expired");
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/model/Driver.java b/src/main/java/org/traccar/model/Driver.java
index b9e023088..ca5714e51 100644
--- a/src/main/java/org/traccar/model/Driver.java
+++ b/src/main/java/org/traccar/model/Driver.java
@@ -38,7 +38,7 @@ public class Driver extends ExtendedModel {
}
public void setUniqueId(String uniqueId) {
- this.uniqueId = uniqueId;
+ this.uniqueId = uniqueId.trim();
}
}
diff --git a/src/main/java/org/traccar/model/Event.java b/src/main/java/org/traccar/model/Event.java
index 6e3953fda..0e851d748 100644
--- a/src/main/java/org/traccar/model/Event.java
+++ b/src/main/java/org/traccar/model/Event.java
@@ -52,6 +52,7 @@ public class Event extends Message {
public static final String TYPE_DEVICE_OVERSPEED = "deviceOverspeed";
public static final String TYPE_DEVICE_FUEL_DROP = "deviceFuelDrop";
+ public static final String TYPE_DEVICE_FUEL_INCREASE = "deviceFuelIncrease";
public static final String TYPE_GEOFENCE_ENTER = "geofenceEnter";
public static final String TYPE_GEOFENCE_EXIT = "geofenceExit";
@@ -62,10 +63,9 @@ public class Event extends Message {
public static final String TYPE_IGNITION_OFF = "ignitionOff";
public static final String TYPE_MAINTENANCE = "maintenance";
-
public static final String TYPE_TEXT_MESSAGE = "textMessage";
-
public static final String TYPE_DRIVER_CHANGED = "driverChanged";
+ public static final String TYPE_MEDIA = "media";
private Date eventTime;
diff --git a/src/main/java/org/traccar/model/ExtendedModel.java b/src/main/java/org/traccar/model/ExtendedModel.java
index 8353d0e66..d5cd094da 100644
--- a/src/main/java/org/traccar/model/ExtendedModel.java
+++ b/src/main/java/org/traccar/model/ExtendedModel.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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,17 +17,22 @@ package org.traccar.model;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Objects;
public class ExtendedModel extends BaseModel {
private Map<String, Object> attributes = new LinkedHashMap<>();
+ public boolean hasAttribute(String key) {
+ return attributes.containsKey(key);
+ }
+
public Map<String, Object> getAttributes() {
return attributes;
}
public void setAttributes(Map<String, Object> attributes) {
- this.attributes = attributes;
+ this.attributes = Objects.requireNonNullElseGet(attributes, LinkedHashMap::new);
}
public void set(String key, Boolean value) {
@@ -84,17 +89,27 @@ public class ExtendedModel extends BaseModel {
}
}
- public String getString(String key) {
+ public String getString(String key, String defaultValue) {
if (attributes.containsKey(key)) {
- return (String) attributes.get(key);
+ Object value = attributes.get(key);
+ return value != null ? value.toString() : null;
} else {
- return null;
+ return defaultValue;
}
}
+ public String getString(String key) {
+ return getString(key, null);
+ }
+
public double getDouble(String key) {
if (attributes.containsKey(key)) {
- return ((Number) attributes.get(key)).doubleValue();
+ Object value = attributes.get(key);
+ if (value instanceof Number) {
+ return ((Number) attributes.get(key)).doubleValue();
+ } else {
+ return Double.parseDouble(value.toString());
+ }
} else {
return 0.0;
}
@@ -102,7 +117,12 @@ public class ExtendedModel extends BaseModel {
public boolean getBoolean(String key) {
if (attributes.containsKey(key)) {
- return (Boolean) attributes.get(key);
+ Object value = attributes.get(key);
+ if (value instanceof Boolean) {
+ return (Boolean) attributes.get(key);
+ } else {
+ return Boolean.parseBoolean(value.toString());
+ }
} else {
return false;
}
@@ -110,7 +130,12 @@ public class ExtendedModel extends BaseModel {
public int getInteger(String key) {
if (attributes.containsKey(key)) {
- return ((Number) attributes.get(key)).intValue();
+ Object value = attributes.get(key);
+ if (value instanceof Number) {
+ return ((Number) attributes.get(key)).intValue();
+ } else {
+ return Integer.parseInt(value.toString());
+ }
} else {
return 0;
}
@@ -118,7 +143,12 @@ public class ExtendedModel extends BaseModel {
public long getLong(String key) {
if (attributes.containsKey(key)) {
- return ((Number) attributes.get(key)).longValue();
+ Object value = attributes.get(key);
+ if (value instanceof Number) {
+ return ((Number) attributes.get(key)).longValue();
+ } else {
+ return Long.parseLong(value.toString());
+ }
} else {
return 0;
}
diff --git a/src/main/java/org/traccar/model/Geofence.java b/src/main/java/org/traccar/model/Geofence.java
index 5b857580d..ca6293651 100644
--- a/src/main/java/org/traccar/model/Geofence.java
+++ b/src/main/java/org/traccar/model/Geofence.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,25 +15,30 @@
*/
package org.traccar.model;
-import java.text.ParseException;
-
-import org.traccar.Context;
-import org.traccar.config.Keys;
-import org.traccar.storage.QueryIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import org.traccar.geofence.GeofenceCircle;
import org.traccar.geofence.GeofenceGeometry;
import org.traccar.geofence.GeofencePolygon;
import org.traccar.geofence.GeofencePolyline;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.traccar.storage.QueryIgnore;
import org.traccar.storage.StorageName;
+import java.text.ParseException;
+
@StorageName("tc_geofences")
-public class Geofence extends ScheduledModel {
+public class Geofence extends ExtendedModel implements Schedulable {
- public static final String TYPE_GEOFENCE_CILCLE = "geofenceCircle";
- public static final String TYPE_GEOFENCE_POLYGON = "geofencePolygon";
- public static final String TYPE_GEOFENCE_POLYLINE = "geofencePolyline";
+ private long calendarId;
+
+ @Override
+ public long getCalendarId() {
+ return calendarId;
+ }
+
+ @Override
+ public void setCalendarId(long calendarId) {
+ this.calendarId = calendarId;
+ }
private String name;
@@ -68,9 +73,7 @@ public class Geofence extends ScheduledModel {
} else if (area.startsWith("POLYGON")) {
geometry = new GeofencePolygon(area);
} else if (area.startsWith("LINESTRING")) {
- final double distance = getDouble("polylineDistance");
- geometry = new GeofencePolyline(area, distance > 0 ? distance
- : Context.getConfig().getDouble(Keys.GEOFENCE_POLYLINE_DISTANCE));
+ geometry = new GeofencePolyline(area);
} else {
throw new ParseException("Unknown geometry type", 0);
}
@@ -92,4 +95,5 @@ public class Geofence extends ScheduledModel {
area = geometry.toWkt();
this.geometry = geometry;
}
+
}
diff --git a/src/main/java/org/traccar/model/Network.java b/src/main/java/org/traccar/model/Network.java
index 4d67fc5d8..b31c53c38 100644
--- a/src/main/java/org/traccar/model/Network.java
+++ b/src/main/java/org/traccar/model/Network.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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.
@@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Objects;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Network {
@@ -118,4 +119,27 @@ public class Network {
wifiAccessPoints.add(wifiAccessPoint);
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Network network = (Network) o;
+ return Objects.equals(homeMobileCountryCode, network.homeMobileCountryCode)
+ && Objects.equals(homeMobileNetworkCode, network.homeMobileNetworkCode)
+ && Objects.equals(radioType, network.radioType)
+ && Objects.equals(carrier, network.carrier)
+ && Objects.equals(cellTowers, network.cellTowers)
+ && Objects.equals(wifiAccessPoints, network.wifiAccessPoints);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ homeMobileCountryCode, homeMobileNetworkCode, radioType, carrier, cellTowers, wifiAccessPoints);
+ }
+
}
diff --git a/src/main/java/org/traccar/model/Notification.java b/src/main/java/org/traccar/model/Notification.java
index 95e446132..6dcd9c9de 100644
--- a/src/main/java/org/traccar/model/Notification.java
+++ b/src/main/java/org/traccar/model/Notification.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,7 +24,19 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import org.traccar.storage.StorageName;
@StorageName("tc_notifications")
-public class Notification extends ScheduledModel {
+public class Notification extends ExtendedModel implements Schedulable {
+
+ private long calendarId;
+
+ @Override
+ public long getCalendarId() {
+ return calendarId;
+ }
+
+ @Override
+ public void setCalendarId(long calendarId) {
+ this.calendarId = calendarId;
+ }
private boolean always;
@@ -46,6 +58,16 @@ public class Notification extends ScheduledModel {
this.type = type;
}
+ private long commandId;
+
+ public long getCommandId() {
+ return commandId;
+ }
+
+ public void setCommandId(long commandId) {
+ this.commandId = commandId;
+ }
+
private String notificators;
public String getNotificators() {
diff --git a/src/main/java/org/traccar/model/Permission.java b/src/main/java/org/traccar/model/Permission.java
index ad0176b39..0b2f0584f 100644
--- a/src/main/java/org/traccar/model/Permission.java
+++ b/src/main/java/org/traccar/model/Permission.java
@@ -31,12 +31,12 @@ import org.traccar.storage.QueryIgnore;
public class Permission {
- private static final Map<String, Class<?>> CLASSES = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ private static final Map<String, Class<? extends BaseModel>> CLASSES = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
static {
try {
for (Class<?> clazz : ClassScanner.findSubclasses(BaseModel.class)) {
- CLASSES.put(clazz.getSimpleName(), clazz);
+ CLASSES.put(clazz.getSimpleName(), (Class<? extends BaseModel>) clazz);
}
} catch (IOException | ReflectiveOperationException | URISyntaxException e) {
throw new RuntimeException(e);
@@ -45,23 +45,25 @@ public class Permission {
private final LinkedHashMap<String, Long> data;
- private final Class<?> ownerClass;
+ private final Class<? extends BaseModel> ownerClass;
private final long ownerId;
- private final Class<?> propertyClass;
+ private final Class<? extends BaseModel> propertyClass;
private final long propertyId;
public Permission(LinkedHashMap<String, Long> data) {
this.data = data;
var iterator = data.entrySet().iterator();
var owner = iterator.next();
- ownerClass = CLASSES.get(owner.getKey().substring(0, owner.getKey().length() - 2));
+ ownerClass = getKeyClass(owner.getKey());
ownerId = owner.getValue();
var property = iterator.next();
- propertyClass = CLASSES.get(property.getKey().substring(0, property.getKey().length() - 2));
+ propertyClass = getKeyClass(property.getKey());
propertyId = property.getValue();
}
- public Permission(Class<?> ownerClass, long ownerId, Class<?> propertyClass, long propertyId) {
+ public Permission(
+ Class<? extends BaseModel> ownerClass, long ownerId,
+ Class<? extends BaseModel> propertyClass, long propertyId) {
this.ownerClass = ownerClass;
this.ownerId = ownerId;
this.propertyClass = propertyClass;
@@ -71,7 +73,11 @@ public class Permission {
data.put(getKey(propertyClass), propertyId);
}
- private static String getKey(Class<?> clazz) {
+ public static Class<? extends BaseModel> getKeyClass(String key) {
+ return CLASSES.get(key.substring(0, key.length() - 2));
+ }
+
+ public static String getKey(Class<?> clazz) {
return Introspector.decapitalize(clazz.getSimpleName()) + "Id";
}
@@ -105,7 +111,7 @@ public class Permission {
@QueryIgnore
@JsonIgnore
- public Class<?> getOwnerClass() {
+ public Class<? extends BaseModel> getOwnerClass() {
return ownerClass;
}
@@ -117,7 +123,7 @@ public class Permission {
@QueryIgnore
@JsonIgnore
- public Class<?> getPropertyClass() {
+ public Class<? extends BaseModel> getPropertyClass() {
return propertyClass;
}
diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java
index 348370e2c..6685cab95 100644
--- a/src/main/java/org/traccar/model/Position.java
+++ b/src/main/java/org/traccar/model/Position.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
package org.traccar.model;
import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.traccar.storage.QueryIgnore;
@@ -40,7 +42,7 @@ public class Position extends Message {
public static final String KEY_ODOMETER = "odometer"; // meters
public static final String KEY_ODOMETER_SERVICE = "serviceOdometer"; // meters
public static final String KEY_ODOMETER_TRIP = "tripOdometer"; // meters
- public static final String KEY_HOURS = "hours";
+ public static final String KEY_HOURS = "hours"; // milliseconds
public static final String KEY_STEPS = "steps";
public static final String KEY_HEART_RATE = "heartRate";
public static final String KEY_INPUT = "input";
@@ -83,12 +85,14 @@ public class Position extends Message {
public static final String KEY_OPERATOR = "operator";
public static final String KEY_COMMAND = "command";
public static final String KEY_BLOCKED = "blocked";
+ public static final String KEY_LOCK = "lock";
public static final String KEY_DOOR = "door";
public static final String KEY_AXLE_WEIGHT = "axleWeight";
public static final String KEY_G_SENSOR = "gSensor";
public static final String KEY_ICCID = "iccid";
public static final String KEY_PHONE = "phone";
public static final String KEY_SPEED_LIMIT = "speedLimit";
+ public static final String KEY_DRIVING_TIME = "drivingTime";
public static final String KEY_DTCS = "dtcs";
public static final String KEY_OBD_SPEED = "obdSpeed"; // knots
@@ -97,6 +101,7 @@ public class Position extends Message {
public static final String KEY_RESULT = "result";
public static final String KEY_DRIVER_UNIQUE_ID = "driverUniqueId";
+ public static final String KEY_CARD = "card";
// Start with 1 not 0
public static final String PREFIX_TEMP = "temp";
@@ -150,7 +155,6 @@ public class Position extends Message {
public Position(String protocol) {
this.protocol = protocol;
- this.serverTime = new Date();
}
private String protocol;
@@ -228,6 +232,9 @@ public class Position extends Message {
}
public void setLatitude(double latitude) {
+ if (latitude < -90 || latitude > 90) {
+ throw new IllegalArgumentException("Latitude out of range");
+ }
this.latitude = latitude;
}
@@ -238,6 +245,9 @@ public class Position extends Message {
}
public void setLongitude(double longitude) {
+ if (longitude < -180 || longitude > 180) {
+ throw new IllegalArgumentException("Longitude out of range");
+ }
this.longitude = longitude;
}
@@ -301,6 +311,20 @@ public class Position extends Message {
this.network = network;
}
+ private List<Long> geofenceIds;
+
+ public List<Long> getGeofenceIds() {
+ return geofenceIds;
+ }
+
+ public void setGeofenceIds(List<? extends Number> geofenceIds) {
+ if (geofenceIds != null) {
+ this.geofenceIds = geofenceIds.stream().map(Number::longValue).collect(Collectors.toList());
+ } else {
+ this.geofenceIds = null;
+ }
+ }
+
@JsonIgnore
@QueryIgnore
@Override
diff --git a/src/main/java/org/traccar/model/QueuedCommand.java b/src/main/java/org/traccar/model/QueuedCommand.java
new file mode 100644
index 000000000..96a1eca4b
--- /dev/null
+++ b/src/main/java/org/traccar/model/QueuedCommand.java
@@ -0,0 +1,46 @@
+/*
+ * 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.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import org.traccar.storage.StorageName;
+
+import java.util.HashMap;
+
+@StorageName("tc_commands_queue")
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class QueuedCommand extends BaseCommand {
+
+ public static QueuedCommand fromCommand(Command command) {
+ QueuedCommand queuedCommand = new QueuedCommand();
+ queuedCommand.setDeviceId(command.getDeviceId());
+ queuedCommand.setType(command.getType());
+ queuedCommand.setTextChannel(command.getTextChannel());
+ queuedCommand.setAttributes(new HashMap<>(command.getAttributes()));
+ return queuedCommand;
+ }
+
+ public Command toCommand() {
+ Command command = new Command();
+ command.setDeviceId(getDeviceId());
+ command.setType(getType());
+ command.setDescription("");
+ command.setTextChannel(getTextChannel());
+ command.setAttributes(new HashMap<>(getAttributes()));
+ return command;
+ }
+
+}
diff --git a/src/main/java/org/traccar/model/Report.java b/src/main/java/org/traccar/model/Report.java
new file mode 100644
index 000000000..2ee7ae288
--- /dev/null
+++ b/src/main/java/org/traccar/model/Report.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2022 - 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.model;
+
+import org.traccar.storage.StorageName;
+
+@StorageName("tc_reports")
+public class Report extends ExtendedModel implements Schedulable {
+
+ private long calendarId;
+
+ @Override
+ public long getCalendarId() {
+ return calendarId;
+ }
+
+ @Override
+ public void setCalendarId(long calendarId) {
+ this.calendarId = calendarId;
+ }
+
+ private String type;
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ private String description;
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+}
diff --git a/src/main/java/org/traccar/model/ScheduledModel.java b/src/main/java/org/traccar/model/Schedulable.java
index 9e6a4b9a6..331e77583 100644
--- a/src/main/java/org/traccar/model/ScheduledModel.java
+++ b/src/main/java/org/traccar/model/Schedulable.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,7 @@
*/
package org.traccar.model;
-public class ScheduledModel extends ExtendedModel {
-
- private long calendarId;
-
- public long getCalendarId() {
- return calendarId;
- }
-
- public void setCalendarId(long calendarId) {
- this.calendarId = calendarId;
- }
+public interface Schedulable {
+ long getCalendarId();
+ void setCalendarId(long calendarId);
}
diff --git a/src/main/java/org/traccar/model/Server.java b/src/main/java/org/traccar/model/Server.java
index b48e84939..6442186b6 100644
--- a/src/main/java/org/traccar/model/Server.java
+++ b/src/main/java/org/traccar/model/Server.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,13 +16,13 @@
package org.traccar.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import org.traccar.Context;
+
import org.traccar.storage.QueryIgnore;
import org.traccar.storage.StorageName;
@StorageName("tc_servers")
@JsonIgnoreProperties(ignoreUnknown = true)
-public class Server extends ExtendedModel {
+public class Server extends ExtendedModel implements UserRestrictions {
private boolean registration;
@@ -36,6 +36,7 @@ public class Server extends ExtendedModel {
private boolean readonly;
+ @Override
public boolean getReadonly() {
return readonly;
}
@@ -46,6 +47,7 @@ public class Server extends ExtendedModel {
private boolean deviceReadonly;
+ @Override
public boolean getDeviceReadonly() {
return deviceReadonly;
}
@@ -84,6 +86,16 @@ public class Server extends ExtendedModel {
this.mapUrl = mapUrl;
}
+ private String overlayUrl;
+
+ public String getOverlayUrl() {
+ return overlayUrl;
+ }
+
+ public void setOverlayUrl(String overlayUrl) {
+ this.overlayUrl = overlayUrl;
+ }
+
private double latitude;
public double getLatitude() {
@@ -146,6 +158,7 @@ public class Server extends ExtendedModel {
private boolean limitCommands;
+ @Override
public boolean getLimitCommands() {
return limitCommands;
}
@@ -156,6 +169,7 @@ public class Server extends ExtendedModel {
private boolean disableReports;
+ @Override
public boolean getDisableReports() {
return disableReports;
}
@@ -164,6 +178,17 @@ public class Server extends ExtendedModel {
this.disableReports = disableReports;
}
+ private boolean fixedEmail;
+
+ @Override
+ public boolean getFixedEmail() {
+ return fixedEmail;
+ }
+
+ public void setFixedEmail(boolean fixedEmail) {
+ this.fixedEmail = fixedEmail;
+ }
+
private String poiLayer;
public String getPoiLayer() {
@@ -189,9 +214,87 @@ public class Server extends ExtendedModel {
return getClass().getPackage().getImplementationVersion();
}
+ private boolean emailEnabled;
+
+ @QueryIgnore
+ public void setEmailEnabled(boolean emailEnabled) {
+ this.emailEnabled = emailEnabled;
+ }
+
@QueryIgnore
public Boolean getEmailEnabled() {
- return Context.getMailManager().getEmailEnabled();
+ return emailEnabled;
+ }
+
+ private boolean geocoderEnabled;
+
+ private boolean textEnabled;
+
+ @QueryIgnore
+ public void setTextEnabled(boolean textEnabled) {
+ this.textEnabled = textEnabled;
+ }
+
+ @QueryIgnore
+ public Boolean getTextEnabled() {
+ return textEnabled;
+ }
+
+ @QueryIgnore
+ public void setGeocoderEnabled(boolean geocoderEnabled) {
+ this.geocoderEnabled = geocoderEnabled;
+ }
+
+ @QueryIgnore
+ public boolean getGeocoderEnabled() {
+ return geocoderEnabled;
+ }
+
+ private long[] storageSpace;
+
+ @QueryIgnore
+ public long[] getStorageSpace() {
+ return storageSpace;
+ }
+
+ @QueryIgnore
+ public void setStorageSpace(long[] storageSpace) {
+ this.storageSpace = storageSpace;
+ }
+
+ private boolean newServer;
+
+ @QueryIgnore
+ public boolean getNewServer() {
+ return newServer;
+ }
+
+ @QueryIgnore
+ public void setNewServer(boolean newServer) {
+ this.newServer = newServer;
+ }
+
+ private boolean openIdEnabled;
+
+ @QueryIgnore
+ public boolean getOpenIdEnabled() {
+ return openIdEnabled;
+ }
+
+ @QueryIgnore
+ public void setOpenIdEnabled(boolean openIdEnabled) {
+ this.openIdEnabled = openIdEnabled;
}
+ private boolean openIdForce;
+
+ @QueryIgnore
+ public boolean getOpenIdForce() {
+ return openIdForce;
+ }
+
+ @QueryIgnore
+ public void setOpenIdForce(boolean openIdForce) {
+ this.openIdForce = openIdForce;
+ }
}
diff --git a/src/main/java/org/traccar/model/User.java b/src/main/java/org/traccar/model/User.java
index 464d0cbfe..0540f16d7 100644
--- a/src/main/java/org/traccar/model/User.java
+++ b/src/main/java/org/traccar/model/User.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 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,7 +17,6 @@ package org.traccar.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
-import org.traccar.storage.QueryExtended;
import org.traccar.storage.QueryIgnore;
import org.traccar.helper.Hashing;
import org.traccar.storage.StorageName;
@@ -25,7 +24,7 @@ import org.traccar.storage.StorageName;
import java.util.Date;
@StorageName("tc_users")
-public class User extends ExtendedModel {
+public class User extends ExtendedModel implements UserRestrictions, Disableable {
private String name;
@@ -64,11 +63,12 @@ public class User extends ExtendedModel {
}
public void setPhone(String phone) {
- this.phone = phone;
+ this.phone = phone != null ? phone.trim() : null;
}
private boolean readonly;
+ @Override
public boolean getReadonly() {
return readonly;
}
@@ -79,6 +79,12 @@ public class User extends ExtendedModel {
private boolean administrator;
+ @QueryIgnore
+ @JsonIgnore
+ public boolean getManager() {
+ return userLimit != 0;
+ }
+
public boolean getAdministrator() {
return administrator;
}
@@ -149,20 +155,24 @@ public class User extends ExtendedModel {
private boolean disabled;
+ @Override
public boolean getDisabled() {
return disabled;
}
+ @Override
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
private Date expirationTime;
+ @Override
public Date getExpirationTime() {
return expirationTime;
}
+ @Override
public void setExpirationTime(Date expirationTime) {
this.expirationTime = expirationTime;
}
@@ -189,6 +199,7 @@ public class User extends ExtendedModel {
private boolean deviceReadonly;
+ @Override
public boolean getDeviceReadonly() {
return deviceReadonly;
}
@@ -197,25 +208,9 @@ public class User extends ExtendedModel {
this.deviceReadonly = deviceReadonly;
}
- private String token;
-
- public String getToken() {
- return token;
- }
-
- public void setToken(String token) {
- if (token != null && !token.isEmpty()) {
- if (!token.matches("^[a-zA-Z0-9-]{16,}$")) {
- throw new IllegalArgumentException("Illegal token");
- }
- this.token = token;
- } else {
- this.token = null;
- }
- }
-
private boolean limitCommands;
+ @Override
public boolean getLimitCommands() {
return limitCommands;
}
@@ -224,10 +219,9 @@ public class User extends ExtendedModel {
this.limitCommands = limitCommands;
}
- private String poiLayer;
-
private boolean disableReports;
+ @Override
public boolean getDisableReports() {
return disableReports;
}
@@ -236,6 +230,19 @@ public class User extends ExtendedModel {
this.disableReports = disableReports;
}
+ private boolean fixedEmail;
+
+ @Override
+ public boolean getFixedEmail() {
+ return fixedEmail;
+ }
+
+ public void setFixedEmail(boolean fixedEmail) {
+ this.fixedEmail = fixedEmail;
+ }
+
+ private String poiLayer;
+
public String getPoiLayer() {
return poiLayer;
}
@@ -261,12 +268,12 @@ public class User extends ExtendedModel {
private String hashedPassword;
@JsonIgnore
- @QueryExtended
+ @QueryIgnore
public String getHashedPassword() {
return hashedPassword;
}
- @QueryExtended
+ @QueryIgnore
public void setHashedPassword(String hashedPassword) {
this.hashedPassword = hashedPassword;
}
@@ -274,12 +281,12 @@ public class User extends ExtendedModel {
private String salt;
@JsonIgnore
- @QueryExtended
+ @QueryIgnore
public String getSalt() {
return salt;
}
- @QueryExtended
+ @QueryIgnore
public void setSalt(String salt) {
this.salt = salt;
}
diff --git a/src/main/java/org/traccar/model/UserRestrictions.java b/src/main/java/org/traccar/model/UserRestrictions.java
new file mode 100644
index 000000000..1fcc5682e
--- /dev/null
+++ b/src/main/java/org/traccar/model/UserRestrictions.java
@@ -0,0 +1,24 @@
+/*
+ * 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.model;
+
+public interface UserRestrictions {
+ boolean getReadonly();
+ boolean getDeviceReadonly();
+ boolean getLimitCommands();
+ boolean getDisableReports();
+ boolean getFixedEmail();
+}
diff --git a/src/main/java/org/traccar/model/WifiAccessPoint.java b/src/main/java/org/traccar/model/WifiAccessPoint.java
index 87a77f3c0..e28c1b935 100644
--- a/src/main/java/org/traccar/model/WifiAccessPoint.java
+++ b/src/main/java/org/traccar/model/WifiAccessPoint.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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.model;
import com.fasterxml.jackson.annotation.JsonInclude;
+import java.util.Objects;
+
@JsonInclude(JsonInclude.Include.NON_NULL)
public class WifiAccessPoint {
@@ -63,4 +65,23 @@ public class WifiAccessPoint {
this.channel = channel;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ WifiAccessPoint that = (WifiAccessPoint) o;
+ return Objects.equals(macAddress, that.macAddress)
+ && Objects.equals(signalStrength, that.signalStrength)
+ && Objects.equals(channel, that.channel);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(macAddress, signalStrength, channel);
+ }
+
}
diff --git a/src/main/java/org/traccar/notification/EventForwarder.java b/src/main/java/org/traccar/notification/EventForwarder.java
deleted file mode 100644
index c908fedbd..000000000
--- a/src/main/java/org/traccar/notification/EventForwarder.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2016 - 2020 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.notification;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.config.Keys;
-import org.traccar.model.Device;
-import org.traccar.model.Event;
-import org.traccar.model.Geofence;
-import org.traccar.model.Maintenance;
-import org.traccar.model.Position;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.Invocation;
-import javax.ws.rs.client.InvocationCallback;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-public class EventForwarder {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(EventForwarder.class);
-
- private final String url;
- private final String header;
-
- public EventForwarder() {
- url = Context.getConfig().getString(Keys.EVENT_FORWARD_URL);
- header = Context.getConfig().getString(Keys.EVENT_FORWARD_HEADERS);
- }
-
- private static final String KEY_POSITION = "position";
- private static final String KEY_EVENT = "event";
- private static final String KEY_GEOFENCE = "geofence";
- private static final String KEY_DEVICE = "device";
- private static final String KEY_MAINTENANCE = "maintenance";
- private static final String KEY_USERS = "users";
-
- public final void forwardEvent(Event event, Position position, Set<Long> users) {
-
- Invocation.Builder requestBuilder = Context.getClient().target(url).request();
-
- if (header != null && !header.isEmpty()) {
- for (String line: header.split("\\r?\\n")) {
- String[] values = line.split(":", 2);
- requestBuilder.header(values[0].trim(), values[1].trim());
- }
- }
-
- LOGGER.debug("Event forwarding initiated");
- requestBuilder.async().post(
- Entity.json(preparePayload(event, position, users)), new InvocationCallback<Object>() {
- @Override
- public void completed(Object o) {
- LOGGER.debug("Event forwarding succeeded");
- }
-
- @Override
- public void failed(Throwable throwable) {
- LOGGER.warn("Event forwarding failed", throwable);
- }
- });
- }
-
- protected Map<String, Object> preparePayload(Event event, Position position, Set<Long> users) {
- Map<String, Object> data = new HashMap<>();
- data.put(KEY_EVENT, event);
- if (position != null) {
- data.put(KEY_POSITION, position);
- }
- Device device = Context.getIdentityManager().getById(event.getDeviceId());
- if (device != null) {
- data.put(KEY_DEVICE, device);
- }
- if (event.getGeofenceId() != 0) {
- Geofence geofence = Context.getGeofenceManager().getById(event.getGeofenceId());
- if (geofence != null) {
- data.put(KEY_GEOFENCE, geofence);
- }
- }
- if (event.getMaintenanceId() != 0) {
- Maintenance maintenance = Context.getMaintenancesManager().getById(event.getMaintenanceId());
- if (maintenance != null) {
- data.put(KEY_MAINTENANCE, maintenance);
- }
- }
- data.put(KEY_USERS, Context.getUsersManager().getItems(users));
- return data;
- }
-
-}
diff --git a/src/main/java/org/traccar/notification/NotificationFormatter.java b/src/main/java/org/traccar/notification/NotificationFormatter.java
index 9a6723a71..85e8a54bb 100644
--- a/src/main/java/org/traccar/notification/NotificationFormatter.java
+++ b/src/main/java/org/traccar/notification/NotificationFormatter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,50 +17,59 @@
package org.traccar.notification;
import org.apache.velocity.VelocityContext;
-import org.traccar.Context;
+import org.traccar.helper.model.UserUtil;
import org.traccar.model.Device;
import org.traccar.model.Event;
+import org.traccar.model.Geofence;
+import org.traccar.model.Maintenance;
import org.traccar.model.Position;
+import org.traccar.model.Server;
import org.traccar.model.User;
-import org.traccar.reports.ReportUtils;
+import org.traccar.session.cache.CacheManager;
-public final class NotificationFormatter {
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
- private NotificationFormatter() {
+@Singleton
+public class NotificationFormatter {
+
+ private final CacheManager cacheManager;
+ private final TextTemplateFormatter textTemplateFormatter;
+
+ @Inject
+ public NotificationFormatter(
+ CacheManager cacheManager, TextTemplateFormatter textTemplateFormatter) {
+ this.cacheManager = cacheManager;
+ this.textTemplateFormatter = textTemplateFormatter;
}
- public static VelocityContext prepareContext(long userId, Event event, Position position) {
+ public NotificationMessage formatMessage(User user, Event event, Position position, String templatePath) {
- User user = Context.getPermissionsManager().getUser(userId);
- Device device = Context.getIdentityManager().getById(event.getDeviceId());
+ Server server = cacheManager.getServer();
+ Device device = cacheManager.getObject(Device.class, event.getDeviceId());
- VelocityContext velocityContext = TextTemplateFormatter.prepareContext(user);
+ VelocityContext velocityContext = textTemplateFormatter.prepareContext(server, user);
velocityContext.put("device", device);
velocityContext.put("event", event);
if (position != null) {
velocityContext.put("position", position);
- velocityContext.put("speedUnit", ReportUtils.getSpeedUnit(userId));
- velocityContext.put("distanceUnit", ReportUtils.getDistanceUnit(userId));
- velocityContext.put("volumeUnit", ReportUtils.getVolumeUnit(userId));
+ velocityContext.put("speedUnit", UserUtil.getSpeedUnit(server, user));
+ velocityContext.put("distanceUnit", UserUtil.getDistanceUnit(server, user));
+ velocityContext.put("volumeUnit", UserUtil.getVolumeUnit(server, user));
}
if (event.getGeofenceId() != 0) {
- velocityContext.put("geofence", Context.getGeofenceManager().getById(event.getGeofenceId()));
+ velocityContext.put("geofence", cacheManager.getObject(Geofence.class, event.getGeofenceId()));
}
if (event.getMaintenanceId() != 0) {
- velocityContext.put("maintenance", Context.getMaintenancesManager().getById(event.getMaintenanceId()));
+ velocityContext.put("maintenance", cacheManager.getObject(Maintenance.class, event.getMaintenanceId()));
}
String driverUniqueId = event.getString(Position.KEY_DRIVER_UNIQUE_ID);
if (driverUniqueId != null) {
- velocityContext.put("driver", Context.getDriversManager().getDriverByUniqueId(driverUniqueId));
+ velocityContext.put("driver", cacheManager.findDriverByUniqueId(device.getId(), driverUniqueId));
}
- return velocityContext;
- }
-
- public static NotificationMessage formatMessage(long userId, Event event, Position position, String templatePath) {
- VelocityContext velocityContext = prepareContext(userId, event, position);
- return TextTemplateFormatter.formatMessage(velocityContext, event.getType(), templatePath);
+ return textTemplateFormatter.formatMessage(velocityContext, event.getType(), templatePath);
}
}
diff --git a/src/main/java/org/traccar/notification/NotificatorManager.java b/src/main/java/org/traccar/notification/NotificatorManager.java
index dfd8cd3d6..8d41ee354 100644
--- a/src/main/java/org/traccar/notification/NotificatorManager.java
+++ b/src/main/java/org/traccar/notification/NotificatorManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,87 +16,67 @@
*/
package org.traccar.notification;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
+import com.google.inject.Injector;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
import org.traccar.model.Typed;
+import org.traccar.notificators.Notificator;
+import org.traccar.notificators.NotificatorCommand;
import org.traccar.notificators.NotificatorFirebase;
import org.traccar.notificators.NotificatorMail;
-import org.traccar.notificators.NotificatorNull;
-import org.traccar.notificators.Notificator;
+import org.traccar.notificators.NotificatorPushover;
import org.traccar.notificators.NotificatorSms;
+import org.traccar.notificators.NotificatorTelegram;
import org.traccar.notificators.NotificatorTraccar;
import org.traccar.notificators.NotificatorWeb;
-import org.traccar.notificators.NotificatorTelegram;
-import org.traccar.notificators.NotificatorPushover;
-public final class NotificatorManager {
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
- private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorManager.class);
+@Singleton
+public class NotificatorManager {
- private static final Notificator NULL_NOTIFICATOR = new NotificatorNull();
+ private static final Map<String, Class<? extends Notificator>> NOTIFICATORS_ALL = Map.of(
+ "command", NotificatorCommand.class,
+ "web", NotificatorWeb.class,
+ "mail", NotificatorMail.class,
+ "sms", NotificatorSms.class,
+ "firebase", NotificatorFirebase.class,
+ "traccar", NotificatorTraccar.class,
+ "telegram", NotificatorTelegram.class,
+ "pushover", NotificatorPushover.class);
- private final Map<String, Notificator> notificators = new HashMap<>();
+ private final Injector injector;
- public NotificatorManager() {
- final String[] types = Context.getConfig().getString("notificator.types", "").split(",");
- for (String type : types) {
- String defaultNotificator = "";
- switch (type) {
- case "web":
- defaultNotificator = NotificatorWeb.class.getCanonicalName();
- break;
- case "mail":
- defaultNotificator = NotificatorMail.class.getCanonicalName();
- break;
- case "sms":
- defaultNotificator = NotificatorSms.class.getCanonicalName();
- break;
- case "firebase":
- defaultNotificator = NotificatorFirebase.class.getCanonicalName();
- break;
- case "traccar":
- defaultNotificator = NotificatorTraccar.class.getCanonicalName();
- break;
- case "telegram":
- defaultNotificator = NotificatorTelegram.class.getCanonicalName();
- break;
- case "pushover":
- defaultNotificator = NotificatorPushover.class.getCanonicalName();
- break;
- default:
- break;
- }
- final String className = Context.getConfig()
- .getString("notificator." + type + ".class", defaultNotificator);
- try {
- notificators.put(type, (Notificator) Class.forName(className).newInstance());
- } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
- LOGGER.warn("Unable to load notificator class for " + type + " " + className + " " + e.getMessage());
- }
+ private final Set<String> types = new HashSet<>();
+
+ @Inject
+ public NotificatorManager(Injector injector, Config config) {
+ this.injector = injector;
+ String types = config.getString(Keys.NOTIFICATOR_TYPES);
+ if (types != null) {
+ this.types.addAll(Arrays.asList(types.split(",")));
}
}
public Notificator getNotificator(String type) {
- final Notificator notificator = notificators.get(type);
- if (notificator == null) {
- LOGGER.warn("No notificator configured for type : " + type);
- return NULL_NOTIFICATOR;
+ var clazz = NOTIFICATORS_ALL.get(type);
+ if (clazz != null && types.contains(type)) {
+ var notificator = injector.getInstance(clazz);
+ if (notificator != null) {
+ return notificator;
+ }
}
- return notificator;
+ throw new RuntimeException("Failed to get notificator " + type);
}
public Set<Typed> getAllNotificatorTypes() {
- Set<Typed> result = new HashSet<>();
- for (String notificator : notificators.keySet()) {
- result.add(new Typed(notificator));
- }
- return result;
+ return types.stream().map(Typed::new).collect(Collectors.toUnmodifiableSet());
}
}
diff --git a/src/main/java/org/traccar/notification/PropertiesProvider.java b/src/main/java/org/traccar/notification/PropertiesProvider.java
index f0078feef..91887b5d4 100644
--- a/src/main/java/org/traccar/notification/PropertiesProvider.java
+++ b/src/main/java/org/traccar/notification/PropertiesProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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.
@@ -16,6 +16,7 @@
package org.traccar.notification;
import org.traccar.config.Config;
+import org.traccar.config.ConfigKey;
import org.traccar.model.ExtendedModel;
public class PropertiesProvider {
@@ -32,36 +33,29 @@ public class PropertiesProvider {
this.extendedModel = extendedModel;
}
- public String getString(String key) {
+ public String getString(ConfigKey<String> key) {
if (config != null) {
return config.getString(key);
} else {
- return extendedModel.getString(key);
+ String result = extendedModel.getString(key.getKey());
+ return result != null ? result : key.getDefaultValue();
}
}
- public String getString(String key, String defaultValue) {
- String value = getString(key);
- if (value == null) {
- value = defaultValue;
- }
- return value;
- }
-
- public int getInteger(String key, int defaultValue) {
+ public int getInteger(ConfigKey<Integer> key) {
if (config != null) {
- return config.getInteger(key, defaultValue);
+ return config.getInteger(key);
} else {
- Object result = extendedModel.getAttributes().get(key);
+ Object result = extendedModel.getAttributes().get(key.getKey());
if (result != null) {
return result instanceof String ? Integer.parseInt((String) result) : (Integer) result;
} else {
- return defaultValue;
+ return key.getDefaultValue();
}
}
}
- public Boolean getBoolean(String key) {
+ public Boolean getBoolean(ConfigKey<Boolean> key) {
if (config != null) {
if (config.hasKey(key)) {
return config.getBoolean(key);
@@ -69,7 +63,7 @@ public class PropertiesProvider {
return null;
}
} else {
- Object result = extendedModel.getAttributes().get(key);
+ Object result = extendedModel.getAttributes().get(key.getKey());
if (result != null) {
return result instanceof String ? Boolean.valueOf((String) result) : (Boolean) result;
} else {
diff --git a/src/main/java/org/traccar/notification/TextTemplateFormatter.java b/src/main/java/org/traccar/notification/TextTemplateFormatter.java
index b7058c824..ab90d76d4 100644
--- a/src/main/java/org/traccar/notification/TextTemplateFormatter.java
+++ b/src/main/java/org/traccar/notification/TextTemplateFormatter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2021 - 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,37 +17,56 @@ package org.traccar.notification;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.tools.generic.DateTool;
import org.apache.velocity.tools.generic.NumberTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.Context;
+import org.traccar.api.signature.TokenManager;
+import org.traccar.helper.model.UserUtil;
+import org.traccar.model.Server;
import org.traccar.model.User;
-import org.traccar.reports.ReportUtils;
+import org.traccar.storage.StorageException;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
import java.util.Locale;
-public final class TextTemplateFormatter {
+@Singleton
+public class TextTemplateFormatter {
private static final Logger LOGGER = LoggerFactory.getLogger(TextTemplateFormatter.class);
- private TextTemplateFormatter() {
+ private final VelocityEngine velocityEngine;
+ private final TokenManager tokenManager;
+
+ @Inject
+ public TextTemplateFormatter(VelocityEngine velocityEngine, TokenManager tokenManager) {
+ this.velocityEngine = velocityEngine;
+ this.tokenManager = tokenManager;
}
- public static VelocityContext prepareContext(User user) {
+ public VelocityContext prepareContext(Server server, User user) {
VelocityContext velocityContext = new VelocityContext();
if (user != null) {
velocityContext.put("user", user);
- velocityContext.put("timezone", ReportUtils.getTimezone(user.getId()));
+ velocityContext.put("timezone", UserUtil.getTimezone(server, user));
+ try {
+ velocityContext.put("token", tokenManager.generateToken(user.getId()));
+ } catch (IOException | GeneralSecurityException | StorageException e) {
+ LOGGER.warn("Token generation failed", e);
+ }
}
- velocityContext.put("webUrl", Context.getVelocityEngine().getProperty("web.url"));
+ velocityContext.put("webUrl", velocityEngine.getProperty("web.url"));
velocityContext.put("dateTool", new DateTool());
velocityContext.put("numberTool", new NumberTool());
velocityContext.put("locale", Locale.getDefault());
@@ -55,23 +74,23 @@ public final class TextTemplateFormatter {
return velocityContext;
}
- public static Template getTemplate(String name, String path) {
+ public Template getTemplate(String name, String path) {
String templateFilePath;
Template template;
try {
templateFilePath = Paths.get(path, name + ".vm").toString();
- template = Context.getVelocityEngine().getTemplate(templateFilePath, StandardCharsets.UTF_8.name());
+ template = velocityEngine.getTemplate(templateFilePath, StandardCharsets.UTF_8.name());
} catch (ResourceNotFoundException error) {
LOGGER.warn("Notification template error", error);
templateFilePath = Paths.get(path, "unknown.vm").toString();
- template = Context.getVelocityEngine().getTemplate(templateFilePath, StandardCharsets.UTF_8.name());
+ template = velocityEngine.getTemplate(templateFilePath, StandardCharsets.UTF_8.name());
}
return template;
}
- public static NotificationMessage formatMessage(VelocityContext velocityContext, String name, String templatePath) {
+ public NotificationMessage formatMessage(VelocityContext velocityContext, String name, String templatePath) {
StringWriter writer = new StringWriter();
getTemplate(name, templatePath).merge(velocityContext, writer);
return new NotificationMessage((String) velocityContext.get("subject"), writer.toString());
diff --git a/src/main/java/org/traccar/notificators/Notificator.java b/src/main/java/org/traccar/notificators/Notificator.java
index dd888bae9..cf71141c0 100644
--- a/src/main/java/org/traccar/notificators/Notificator.java
+++ b/src/main/java/org/traccar/notificators/Notificator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,27 +16,14 @@
*/
package org.traccar.notificators;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.traccar.model.Event;
+import org.traccar.model.Notification;
import org.traccar.model.Position;
+import org.traccar.model.User;
import org.traccar.notification.MessageException;
-public abstract class Notificator {
+public interface Notificator {
- private static final Logger LOGGER = LoggerFactory.getLogger(Notificator.class);
-
- public void sendAsync(final long userId, final Event event, final Position position) {
- new Thread(() -> {
- try {
- sendSync(userId, event, position);
- } catch (MessageException | InterruptedException error) {
- LOGGER.warn("Event send error", error);
- }
- }).start();
- }
-
- public abstract void sendSync(long userId, Event event, Position position)
- throws MessageException, InterruptedException;
+ void send(Notification notification, User user, Event event, Position position) throws MessageException;
}
diff --git a/src/main/java/org/traccar/notificators/NotificatorCommand.java b/src/main/java/org/traccar/notificators/NotificatorCommand.java
new file mode 100644
index 000000000..5dd3313d4
--- /dev/null
+++ b/src/main/java/org/traccar/notificators/NotificatorCommand.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.notificators;
+
+import org.traccar.database.CommandsManager;
+import org.traccar.model.Command;
+import org.traccar.model.Event;
+import org.traccar.model.Notification;
+import org.traccar.model.Position;
+import org.traccar.model.User;
+import org.traccar.notification.MessageException;
+import org.traccar.storage.Storage;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+@Singleton
+public class NotificatorCommand implements Notificator {
+
+ private final Storage storage;
+ private final CommandsManager commandsManager;
+
+ @Inject
+ public NotificatorCommand(Storage storage, CommandsManager commandsManager) {
+ this.storage = storage;
+ this.commandsManager = commandsManager;
+ }
+
+ @Override
+ public void send(Notification notification, User user, Event event, Position position) throws MessageException {
+
+ if (notification == null || notification.getCommandId() <= 0) {
+ throw new MessageException("Saved command not provided");
+ }
+
+ try {
+ Command command = storage.getObject(Command.class, new Request(
+ new Columns.All(), new Condition.Equals("id", notification.getCommandId())));
+ command.setDeviceId(event.getDeviceId());
+ commandsManager.sendCommand(command);
+ } catch (Exception e) {
+ throw new MessageException(e);
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java
index f91ec25a0..be95fb28e 100644
--- a/src/main/java/org/traccar/notificators/NotificatorFirebase.java
+++ b/src/main/java/org/traccar/notificators/NotificatorFirebase.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,88 +16,131 @@
*/
package org.traccar.notificators;
-import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.auth.oauth2.GoogleCredentials;
+import com.google.firebase.FirebaseApp;
+import com.google.firebase.FirebaseOptions;
+import com.google.firebase.messaging.AndroidConfig;
+import com.google.firebase.messaging.AndroidNotification;
+import com.google.firebase.messaging.ApnsConfig;
+import com.google.firebase.messaging.Aps;
+import com.google.firebase.messaging.FirebaseMessaging;
+import com.google.firebase.messaging.FirebaseMessagingException;
+import com.google.firebase.messaging.MessagingErrorCode;
+import com.google.firebase.messaging.MulticastMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.Context;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Event;
+import org.traccar.model.Notification;
import org.traccar.model.Position;
import org.traccar.model.User;
-import org.traccar.notification.NotificationMessage;
+import org.traccar.notification.MessageException;
import org.traccar.notification.NotificationFormatter;
-
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.InvocationCallback;
-
-public class NotificatorFirebase extends Notificator {
+import org.traccar.session.cache.CacheManager;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+@Singleton
+public class NotificatorFirebase implements Notificator {
private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorFirebase.class);
- private final String url;
- private final String key;
+ private final NotificationFormatter notificationFormatter;
+ private final Storage storage;
+ private final CacheManager cacheManager;
- public static class Notification {
- @JsonProperty("title")
- private String title;
- @JsonProperty("body")
- private String body;
- @JsonProperty("sound")
- private String sound;
- }
+ @Inject
+ public NotificatorFirebase(
+ Config config, NotificationFormatter notificationFormatter,
+ Storage storage, CacheManager cacheManager) throws IOException {
- public static class Message {
- @JsonProperty("registration_ids")
- private String[] tokens;
- @JsonProperty("notification")
- private Notification notification;
- }
+ this.notificationFormatter = notificationFormatter;
+ this.storage = storage;
+ this.cacheManager = cacheManager;
- public NotificatorFirebase() {
- this(
- "https://fcm.googleapis.com/fcm/send",
- Context.getConfig().getString(Keys.NOTIFICATOR_FIREBASE_KEY));
- }
+ InputStream serviceAccount = new ByteArrayInputStream(
+ config.getString(Keys.NOTIFICATOR_FIREBASE_SERVICE_ACCOUNT).getBytes());
- protected NotificatorFirebase(String url, String key) {
- this.url = url;
- this.key = key;
+ FirebaseOptions options = FirebaseOptions.builder()
+ .setCredentials(GoogleCredentials.fromStream(serviceAccount))
+ .build();
+
+ FirebaseApp.initializeApp(options);
}
@Override
- public void sendSync(long userId, Event event, Position position) {
- final User user = Context.getPermissionsManager().getUser(userId);
- if (user.getAttributes().containsKey("notificationTokens")) {
-
- NotificationMessage shortMessage = NotificationFormatter.formatMessage(userId, event, position, "short");
-
- Notification notification = new Notification();
- notification.title = shortMessage.getSubject();
- notification.body = shortMessage.getBody();
- notification.sound = "default";
-
- Message message = new Message();
- message.tokens = user.getString("notificationTokens").split("[, ]");
- message.notification = notification;
-
- Context.getClient().target(url).request()
- .header("Authorization", "key=" + key)
- .async().post(Entity.json(message), new InvocationCallback<Object>() {
- @Override
- public void completed(Object o) {
+ public void send(Notification notification, User user, Event event, Position position) throws MessageException {
+ if (user.hasAttribute("notificationTokens")) {
+
+ var shortMessage = notificationFormatter.formatMessage(user, event, position, "short");
+
+ List<String> registrationTokens = new ArrayList<>(
+ Arrays.asList(user.getString("notificationTokens").split("[, ]")));
+
+ MulticastMessage message = MulticastMessage.builder()
+ .setNotification(com.google.firebase.messaging.Notification.builder()
+ .setTitle(shortMessage.getSubject())
+ .setBody(shortMessage.getBody())
+ .build())
+ .setAndroidConfig(AndroidConfig.builder()
+ .setNotification(AndroidNotification.builder()
+ .setSound("default")
+ .build())
+ .build())
+ .setApnsConfig(ApnsConfig.builder()
+ .setAps(Aps.builder()
+ .setSound("default")
+ .build())
+ .build())
+ .addAllTokens(registrationTokens)
+ .putData("eventId", String.valueOf(event.getId()))
+ .build();
+
+ try {
+ var result = FirebaseMessaging.getInstance().sendMulticast(message);
+ List<String> failedTokens = new LinkedList<>();
+ var iterator = result.getResponses().listIterator();
+ while (iterator.hasNext()) {
+ int index = iterator.nextIndex();
+ var response = iterator.next();
+ if (!response.isSuccessful()) {
+ MessagingErrorCode error = response.getException().getMessagingErrorCode();
+ if (error == MessagingErrorCode.INVALID_ARGUMENT || error == MessagingErrorCode.UNREGISTERED) {
+ failedTokens.add(registrationTokens.get(index));
+ }
+ LOGGER.warn("Firebase user {} error", user.getId(), response.getException());
+ }
}
-
- @Override
- public void failed(Throwable throwable) {
- LOGGER.warn("Firebase notification error", throwable);
+ if (!failedTokens.isEmpty()) {
+ registrationTokens.removeAll(failedTokens);
+ if (registrationTokens.isEmpty()) {
+ user.getAttributes().remove("notificationTokens");
+ } else {
+ user.set("notificationTokens", String.join(",", registrationTokens));
+ }
+ storage.updateObject(user, new Request(
+ new Columns.Include("attributes"),
+ new Condition.Equals("id", user.getId())));
+ cacheManager.updateOrInvalidate(true, user);
}
- });
+ } catch (FirebaseMessagingException | StorageException e) {
+ LOGGER.warn("Firebase error", e);
+ }
}
}
- @Override
- public void sendAsync(long userId, Event event, Position position) {
- sendSync(userId, event, position);
- }
-
}
diff --git a/src/main/java/org/traccar/notificators/NotificatorMail.java b/src/main/java/org/traccar/notificators/NotificatorMail.java
index 9b5637ed8..3ab050686 100644
--- a/src/main/java/org/traccar/notificators/NotificatorMail.java
+++ b/src/main/java/org/traccar/notificators/NotificatorMail.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,22 +16,35 @@
*/
package org.traccar.notificators;
-import org.traccar.Context;
+import org.traccar.mail.MailManager;
import org.traccar.model.Event;
+import org.traccar.model.Notification;
import org.traccar.model.Position;
-import org.traccar.notification.NotificationMessage;
+import org.traccar.model.User;
import org.traccar.notification.MessageException;
import org.traccar.notification.NotificationFormatter;
-import javax.mail.MessagingException;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import jakarta.mail.MessagingException;
-public final class NotificatorMail extends Notificator {
+@Singleton
+public class NotificatorMail implements Notificator {
+
+ private final MailManager mailManager;
+ private final NotificationFormatter notificationFormatter;
+
+ @Inject
+ public NotificatorMail(MailManager mailManager, NotificationFormatter notificationFormatter) {
+ this.mailManager = mailManager;
+ this.notificationFormatter = notificationFormatter;
+ }
@Override
- public void sendSync(long userId, Event event, Position position) throws MessageException {
+ public void send(Notification notification, User user, Event event, Position position) throws MessageException {
try {
- NotificationMessage fullMessage = NotificationFormatter.formatMessage(userId, event, position, "full");
- Context.getMailManager().sendMessage(userId, fullMessage.getSubject(), fullMessage.getBody());
+ var fullMessage = notificationFormatter.formatMessage(user, event, position, "full");
+ mailManager.sendMessage(user, false, fullMessage.getSubject(), fullMessage.getBody());
} catch (MessagingException e) {
throw new MessageException(e);
}
diff --git a/src/main/java/org/traccar/notificators/NotificatorNull.java b/src/main/java/org/traccar/notificators/NotificatorNull.java
deleted file mode 100644
index 9364336be..000000000
--- a/src/main/java/org/traccar/notificators/NotificatorNull.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2018 Anton Tananaev (anton@traccar.org)
- * Copyright 2018 Andrey Kunitsyn (andrey@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.notificators;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.model.Event;
-import org.traccar.model.Position;
-
-public final class NotificatorNull extends Notificator {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorNull.class);
-
- @Override
- public void sendAsync(long userId, Event event, Position position) {
- LOGGER.warn("You are using null notificatior, please check your configuration, notification not sent");
- }
-
- @Override
- public void sendSync(long userId, Event event, Position position) {
- LOGGER.warn("You are using null notificatior, please check your configuration, notification not sent");
- }
-
-}
diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java
index 456c2fe4f..9f2a8c94d 100644
--- a/src/main/java/org/traccar/notificators/NotificatorPushover.java
+++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2020 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,22 +16,24 @@
package org.traccar.notificators;
import com.fasterxml.jackson.annotation.JsonProperty;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Event;
+import org.traccar.model.Notification;
import org.traccar.model.Position;
import org.traccar.model.User;
import org.traccar.notification.NotificationFormatter;
-import org.traccar.notification.NotificationMessage;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.InvocationCallback;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.Entity;
-public class NotificatorPushover extends Notificator {
+@Singleton
+public class NotificatorPushover implements Notificator {
- private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorPushover.class);
+ private final NotificationFormatter notificationFormatter;
+ private final Client client;
private final String url;
private final String token;
@@ -50,58 +52,35 @@ public class NotificatorPushover extends Notificator {
private String message;
}
- public NotificatorPushover() {
+ @Inject
+ public NotificatorPushover(Config config, NotificationFormatter notificationFormatter, Client client) {
+ this.notificationFormatter = notificationFormatter;
+ this.client = client;
url = "https://api.pushover.net/1/messages.json";
- token = Context.getConfig().getString(Keys.NOTIFICATOR_PUSHOVER_TOKEN);
- user = Context.getConfig().getString(Keys.NOTIFICATOR_PUSHOVER_USER);
+ token = config.getString(Keys.NOTIFICATOR_PUSHOVER_TOKEN);
+ user = config.getString(Keys.NOTIFICATOR_PUSHOVER_USER);
}
@Override
- public void sendSync(long userId, Event event, Position position) {
+ public void send(Notification notification, User user, Event event, Position position) {
+ var shortMessage = notificationFormatter.formatMessage(user, event, position, "short");
- final User user = Context.getPermissionsManager().getUser(userId);
-
- String device = "";
-
- if (user.getAttributes().containsKey("notificator.pushover.device")) {
- device = user.getString("notificator.pushover.device").replaceAll(" *, *", ",");
- }
+ Message message = new Message();
+ message.token = token;
- if (token == null) {
- LOGGER.warn("Pushover token not found");
- return;
+ message.user = user.getString("pushoverUserKey");
+ if (message.user == null) {
+ message.user = this.user;
}
- if (this.user == null) {
- LOGGER.warn("Pushover user not found");
- return;
+ if (user.hasAttribute("pushoverDeviceNames")) {
+ message.device = user.getString("pushoverDeviceNames").replaceAll(" *, *", ",");
}
- NotificationMessage shortMessage = NotificationFormatter.formatMessage(userId, event, position, "short");
-
- Message message = new Message();
- message.token = token;
- message.user = this.user;
- message.device = device;
message.title = shortMessage.getSubject();
message.message = shortMessage.getBody();
- Context.getClient().target(url).request()
- .async().post(Entity.json(message), new InvocationCallback<Object>() {
- @Override
- public void completed(Object o) {
- }
-
- @Override
- public void failed(Throwable throwable) {
- LOGGER.warn("Pushover API error", throwable);
- }
- });
- }
-
- @Override
- public void sendAsync(long userId, Event event, Position position) {
- sendSync(userId, event, position);
+ client.target(url).request().post(Entity.json(message)).close();
}
}
diff --git a/src/main/java/org/traccar/notificators/NotificatorSms.java b/src/main/java/org/traccar/notificators/NotificatorSms.java
index fb817b112..2b6b20b1b 100644
--- a/src/main/java/org/traccar/notificators/NotificatorSms.java
+++ b/src/main/java/org/traccar/notificators/NotificatorSms.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,37 +16,39 @@
*/
package org.traccar.notificators;
-import org.traccar.Context;
-import org.traccar.Main;
import org.traccar.database.StatisticsManager;
import org.traccar.model.Event;
+import org.traccar.model.Notification;
import org.traccar.model.Position;
import org.traccar.model.User;
import org.traccar.notification.MessageException;
import org.traccar.notification.NotificationFormatter;
-import org.traccar.notification.NotificationMessage;
+import org.traccar.sms.SmsManager;
-public final class NotificatorSms extends Notificator {
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
- @Override
- public void sendAsync(long userId, Event event, Position position) {
- final User user = Context.getPermissionsManager().getUser(userId);
- if (user.getPhone() != null) {
- NotificationMessage shortMessage = NotificationFormatter.formatMessage(userId, event, position, "short");
- Main.getInjector().getInstance(StatisticsManager.class).registerSms();
- Context.getSmsManager().sendMessageAsync(user.getPhone(),
- shortMessage.getBody(), false);
- }
+@Singleton
+public class NotificatorSms implements Notificator {
+
+ private final SmsManager smsManager;
+ private final NotificationFormatter notificationFormatter;
+ private final StatisticsManager statisticsManager;
+
+ @Inject
+ public NotificatorSms(
+ SmsManager smsManager, NotificationFormatter notificationFormatter, StatisticsManager statisticsManager) {
+ this.smsManager = smsManager;
+ this.notificationFormatter = notificationFormatter;
+ this.statisticsManager = statisticsManager;
}
@Override
- public void sendSync(long userId, Event event, Position position) throws MessageException, InterruptedException {
- final User user = Context.getPermissionsManager().getUser(userId);
+ public void send(Notification notification, User user, Event event, Position position) throws MessageException {
if (user.getPhone() != null) {
- NotificationMessage shortMessage = NotificationFormatter.formatMessage(userId, event, position, "short");
- Main.getInjector().getInstance(StatisticsManager.class).registerSms();
- Context.getSmsManager().sendMessageSync(user.getPhone(),
- shortMessage.getBody(), false);
+ var shortMessage = notificationFormatter.formatMessage(user, event, position, "short");
+ statisticsManager.registerSms();
+ smsManager.sendMessage(user.getPhone(), shortMessage.getBody(), false);
}
}
diff --git a/src/main/java/org/traccar/notificators/NotificatorTelegram.java b/src/main/java/org/traccar/notificators/NotificatorTelegram.java
index 70148110c..c91aaa4ff 100644
--- a/src/main/java/org/traccar/notificators/NotificatorTelegram.java
+++ b/src/main/java/org/traccar/notificators/NotificatorTelegram.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2019 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2021 Rafael Miquelino (rafaelmiquelino@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,22 +17,24 @@
package org.traccar.notificators;
import com.fasterxml.jackson.annotation.JsonProperty;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.model.User;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Event;
+import org.traccar.model.Notification;
import org.traccar.model.Position;
+import org.traccar.model.User;
import org.traccar.notification.NotificationFormatter;
-import org.traccar.notification.NotificationMessage;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.InvocationCallback;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.Entity;
-public class NotificatorTelegram extends Notificator {
+@Singleton
+public class NotificatorTelegram implements Notificator {
- private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorTelegram.class);
+ private final NotificationFormatter notificationFormatter;
+ private final Client client;
private final String urlSendText;
private final String urlSendLocation;
@@ -61,29 +63,16 @@ public class NotificatorTelegram extends Notificator {
private int bearing;
}
- public NotificatorTelegram() {
+ @Inject
+ public NotificatorTelegram(Config config, NotificationFormatter notificationFormatter, Client client) {
+ this.notificationFormatter = notificationFormatter;
+ this.client = client;
urlSendText = String.format(
- "https://api.telegram.org/bot%s/sendMessage",
- Context.getConfig().getString(Keys.NOTIFICATOR_TELEGRAM_KEY));
+ "https://api.telegram.org/bot%s/sendMessage", config.getString(Keys.NOTIFICATOR_TELEGRAM_KEY));
urlSendLocation = String.format(
- "https://api.telegram.org/bot%s/sendLocation",
- Context.getConfig().getString(Keys.NOTIFICATOR_TELEGRAM_KEY));
- chatId = Context.getConfig().getString(Keys.NOTIFICATOR_TELEGRAM_CHAT_ID);
- sendLocation = Context.getConfig().getBoolean(Keys.NOTIFICATOR_TELEGRAM_SEND_LOCATION);
- }
-
- private void executeRequest(String url, Object message) {
- Context.getClient().target(url).request()
- .async().post(Entity.json(message), new InvocationCallback<Object>() {
- @Override
- public void completed(Object o) {
- }
-
- @Override
- public void failed(Throwable throwable) {
- LOGGER.warn("Telegram API error", throwable);
- }
- });
+ "https://api.telegram.org/bot%s/sendLocation", config.getString(Keys.NOTIFICATOR_TELEGRAM_KEY));
+ chatId = config.getString(Keys.NOTIFICATOR_TELEGRAM_CHAT_ID);
+ sendLocation = config.getBoolean(Keys.NOTIFICATOR_TELEGRAM_SEND_LOCATION);
}
private LocationMessage createLocationMessage(String messageChatId, Position position) {
@@ -97,9 +86,8 @@ public class NotificatorTelegram extends Notificator {
}
@Override
- public void sendSync(long userId, Event event, Position position) {
- User user = Context.getPermissionsManager().getUser(userId);
- NotificationMessage shortMessage = NotificationFormatter.formatMessage(userId, event, position, "short");
+ public void send(Notification notification, User user, Event event, Position position) {
+ var shortMessage = notificationFormatter.formatMessage(user, event, position, "short");
TextMessage message = new TextMessage();
message.chatId = user.getString("telegramChatId");
@@ -107,15 +95,11 @@ public class NotificatorTelegram extends Notificator {
message.chatId = chatId;
}
message.text = shortMessage.getBody();
- executeRequest(urlSendText, message);
+ client.target(urlSendText).request().post(Entity.json(message)).close();
if (sendLocation && position != null) {
- executeRequest(urlSendLocation, createLocationMessage(message.chatId, position));
+ client.target(urlSendLocation).request().post(
+ Entity.json(createLocationMessage(message.chatId, position))).close();
}
}
- @Override
- public void sendAsync(long userId, Event event, Position position) {
- sendSync(userId, event, position);
- }
-
}
diff --git a/src/main/java/org/traccar/notificators/NotificatorTraccar.java b/src/main/java/org/traccar/notificators/NotificatorTraccar.java
index 5bcd18b5e..e354adccb 100644
--- a/src/main/java/org/traccar/notificators/NotificatorTraccar.java
+++ b/src/main/java/org/traccar/notificators/NotificatorTraccar.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2020 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,15 +15,125 @@
*/
package org.traccar.notificators;
-import org.traccar.Context;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+import org.traccar.model.User;
+import org.traccar.notification.NotificationFormatter;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
-public class NotificatorTraccar extends NotificatorFirebase {
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
- public NotificatorTraccar() {
- super(
- "https://www.traccar.org/push/",
- Context.getConfig().getString(Keys.NOTIFICATOR_TRACCAR_KEY));
+@Singleton
+public class NotificatorTraccar implements Notificator {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorTraccar.class);
+
+ private final NotificationFormatter notificationFormatter;
+ private final Client client;
+ private final Storage storage;
+ private final CacheManager cacheManager;
+
+ private final String url;
+ private final String key;
+
+ public static class NotificationObject {
+ @JsonProperty("title")
+ private String title;
+ @JsonProperty("body")
+ private String body;
+ @JsonProperty("sound")
+ private String sound;
+ }
+
+ public static class Message {
+ @JsonProperty("registration_ids")
+ private String[] tokens;
+ @JsonProperty("notification")
+ private NotificationObject notification;
+ }
+
+ @Inject
+ public NotificatorTraccar(
+ Config config, NotificationFormatter notificationFormatter, Client client,
+ Storage storage, CacheManager cacheManager) {
+ this.notificationFormatter = notificationFormatter;
+ this.client = client;
+ this.storage = storage;
+ this.cacheManager = cacheManager;
+ this.url = "https://www.traccar.org/push/";
+ this.key = config.getString(Keys.NOTIFICATOR_TRACCAR_KEY);
+ }
+
+ @Override
+ public void send(org.traccar.model.Notification notification, User user, Event event, Position position) {
+ if (user.hasAttribute("notificationTokens")) {
+
+ var shortMessage = notificationFormatter.formatMessage(user, event, position, "short");
+
+ NotificationObject item = new NotificationObject();
+ item.title = shortMessage.getSubject();
+ item.body = shortMessage.getBody();
+ item.sound = "default";
+
+ String[] tokenArray = user.getString("notificationTokens").split("[, ]");
+ List<String> registrationTokens = new ArrayList<>(Arrays.asList(tokenArray));
+
+ Message message = new Message();
+ message.tokens = user.getString("notificationTokens").split("[, ]");
+ message.notification = item;
+
+ var request = client.target(url).request().header("Authorization", "key=" + key);
+ try (Response result = request.post(Entity.json(message))) {
+ var json = result.readEntity(JsonObject.class);
+ List<String> failedTokens = new LinkedList<>();
+ var responses = json.getJsonArray("responses");
+ for (int i = 0; i < responses.size(); i++) {
+ var response = responses.getJsonObject(i);
+ if (!response.getBoolean("success")) {
+ var error = response.getJsonObject("error");
+ String errorCode = error.getString("code");
+ if (errorCode.equals("messaging/invalid-argument")
+ || errorCode.equals("messaging/registration-token-not-registered")) {
+ failedTokens.add(registrationTokens.get(i));
+ }
+ LOGGER.warn("Push user {} error - {}", user.getId(), error.getString("message"));
+ }
+ }
+ if (!failedTokens.isEmpty()) {
+ registrationTokens.removeAll(failedTokens);
+ if (registrationTokens.isEmpty()) {
+ user.getAttributes().remove("notificationTokens");
+ } else {
+ user.set("notificationTokens", String.join(",", registrationTokens));
+ }
+ storage.updateObject(user, new Request(
+ new Columns.Include("attributes"),
+ new Condition.Equals("id", user.getId())));
+ cacheManager.updateOrInvalidate(true, user);
+ }
+ } catch (StorageException e) {
+ LOGGER.warn("Push error", e);
+ }
+ }
}
}
diff --git a/src/main/java/org/traccar/notificators/NotificatorWeb.java b/src/main/java/org/traccar/notificators/NotificatorWeb.java
index 1d11c0b46..3a125db3c 100644
--- a/src/main/java/org/traccar/notificators/NotificatorWeb.java
+++ b/src/main/java/org/traccar/notificators/NotificatorWeb.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,15 +16,45 @@
*/
package org.traccar.notificators;
-import org.traccar.Context;
import org.traccar.model.Event;
+import org.traccar.model.Notification;
import org.traccar.model.Position;
+import org.traccar.model.User;
+import org.traccar.notification.NotificationFormatter;
+import org.traccar.session.ConnectionManager;
-public final class NotificatorWeb extends Notificator {
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+@Singleton
+public final class NotificatorWeb implements Notificator {
+
+ private final ConnectionManager connectionManager;
+ private final NotificationFormatter notificationFormatter;
+
+ @Inject
+ public NotificatorWeb(ConnectionManager connectionManager, NotificationFormatter notificationFormatter) {
+ this.connectionManager = connectionManager;
+ this.notificationFormatter = notificationFormatter;
+ }
@Override
- public void sendSync(long userId, Event event, Position position) {
- Context.getConnectionManager().updateEvent(userId, event);
+ public void send(Notification notification, User user, Event event, Position position) {
+
+ Event copy = new Event();
+ copy.setId(event.getId());
+ copy.setDeviceId(event.getDeviceId());
+ copy.setType(event.getType());
+ copy.setEventTime(event.getEventTime());
+ copy.setPositionId(event.getPositionId());
+ copy.setGeofenceId(event.getGeofenceId());
+ copy.setMaintenanceId(event.getMaintenanceId());
+ copy.getAttributes().putAll(event.getAttributes());
+
+ var message = notificationFormatter.formatMessage(user, event, position, "short");
+ copy.set("message", message.getBody());
+
+ connectionManager.updateEvent(true, user.getId(), copy);
}
}
diff --git a/src/main/java/org/traccar/protocol/AdmProtocol.java b/src/main/java/org/traccar/protocol/AdmProtocol.java
index d1d81118c..3856dc906 100644
--- a/src/main/java/org/traccar/protocol/AdmProtocol.java
+++ b/src/main/java/org/traccar/protocol/AdmProtocol.java
@@ -19,17 +19,21 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class AdmProtocol extends BaseProtocol {
- public AdmProtocol() {
+ @Inject
+ public AdmProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_GET_DEVICE_STATUS,
Command.TYPE_CUSTOM);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new AdmFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new AdmProtocolEncoder(AdmProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/AdmProtocolDecoder.java b/src/main/java/org/traccar/protocol/AdmProtocolDecoder.java
index 7e3478704..1f940f7e2 100644
--- a/src/main/java/org/traccar/protocol/AdmProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AdmProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.UnitsConverter;
diff --git a/src/main/java/org/traccar/protocol/AisProtocol.java b/src/main/java/org/traccar/protocol/AisProtocol.java
index 3b9cad7c8..e792a1d3f 100644
--- a/src/main/java/org/traccar/protocol/AisProtocol.java
+++ b/src/main/java/org/traccar/protocol/AisProtocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.string.StringDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class AisProtocol extends BaseProtocol {
- public AisProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public AisProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringDecoder());
pipeline.addLast(new AisProtocolDecoder(AisProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/AisProtocolDecoder.java b/src/main/java/org/traccar/protocol/AisProtocolDecoder.java
index 8970f3d4a..a434e6e33 100644
--- a/src/main/java/org/traccar/protocol/AisProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AisProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitBuffer;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/AlematicsProtocol.java b/src/main/java/org/traccar/protocol/AlematicsProtocol.java
index 8da2356b9..5219607e7 100644
--- a/src/main/java/org/traccar/protocol/AlematicsProtocol.java
+++ b/src/main/java/org/traccar/protocol/AlematicsProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class AlematicsProtocol extends BaseProtocol {
- public AlematicsProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public AlematicsProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new AlematicsFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/AlematicsProtocolDecoder.java b/src/main/java/org/traccar/protocol/AlematicsProtocolDecoder.java
index 25ccf6856..981437191 100644
--- a/src/main/java/org/traccar/protocol/AlematicsProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AlematicsProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/AnytrekProtocol.java b/src/main/java/org/traccar/protocol/AnytrekProtocol.java
index 9bd0c9163..5dce15ce1 100644
--- a/src/main/java/org/traccar/protocol/AnytrekProtocol.java
+++ b/src/main/java/org/traccar/protocol/AnytrekProtocol.java
@@ -19,15 +19,19 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import java.nio.ByteOrder;
+import jakarta.inject.Inject;
+
public class AnytrekProtocol extends BaseProtocol {
- public AnytrekProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public AnytrekProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, 2, 0, true));
pipeline.addLast(new AnytrekProtocolDecoder(AnytrekProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/AnytrekProtocolDecoder.java b/src/main/java/org/traccar/protocol/AnytrekProtocolDecoder.java
index c48f59c90..0f9c2b17a 100644
--- a/src/main/java/org/traccar/protocol/AnytrekProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AnytrekProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/ApelProtocol.java b/src/main/java/org/traccar/protocol/ApelProtocol.java
index 382aa16af..550581b85 100644
--- a/src/main/java/org/traccar/protocol/ApelProtocol.java
+++ b/src/main/java/org/traccar/protocol/ApelProtocol.java
@@ -19,14 +19,18 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import java.nio.ByteOrder;
+import jakarta.inject.Inject;
+
public class ApelProtocol extends BaseProtocol {
- public ApelProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public ApelProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, 4, 0, true));
pipeline.addLast(new ApelProtocolDecoder(ApelProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/ApelProtocolDecoder.java b/src/main/java/org/traccar/protocol/ApelProtocolDecoder.java
index c95a0366a..97ed7de96 100644
--- a/src/main/java/org/traccar/protocol/ApelProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ApelProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Checksum;
diff --git a/src/main/java/org/traccar/protocol/AplicomProtocol.java b/src/main/java/org/traccar/protocol/AplicomProtocol.java
index 2b9dbf97c..48c628d22 100644
--- a/src/main/java/org/traccar/protocol/AplicomProtocol.java
+++ b/src/main/java/org/traccar/protocol/AplicomProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class AplicomProtocol extends BaseProtocol {
- public AplicomProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public AplicomProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new AplicomFrameDecoder());
pipeline.addLast(new AplicomProtocolDecoder(AplicomProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/AplicomProtocolDecoder.java b/src/main/java/org/traccar/protocol/AplicomProtocolDecoder.java
index f11312428..0cd8ca37e 100644
--- a/src/main/java/org/traccar/protocol/AplicomProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AplicomProtocolDecoder.java
@@ -21,8 +21,7 @@ import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.config.Keys;
import org.traccar.helper.Checksum;
@@ -303,7 +302,7 @@ public class AplicomProtocolDecoder extends BaseProtocolDecoder {
decodeEventData(position, buf, event);
}
- if (Context.getConfig().getBoolean(Keys.PROTOCOL_CAN.withPrefix(getProtocolName()))
+ if (getConfig().getBoolean(Keys.PROTOCOL_CAN.withPrefix(getProtocolName()))
&& buf.isReadable() && (selector & 0x1000) != 0 && event == EVENT_DATA) {
decodeCanData(buf, position);
}
diff --git a/src/main/java/org/traccar/protocol/AppelloProtocol.java b/src/main/java/org/traccar/protocol/AppelloProtocol.java
index 1ca4168e4..34055d7e4 100644
--- a/src/main/java/org/traccar/protocol/AppelloProtocol.java
+++ b/src/main/java/org/traccar/protocol/AppelloProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class AppelloProtocol extends BaseProtocol {
- public AppelloProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public AppelloProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/AppelloProtocolDecoder.java b/src/main/java/org/traccar/protocol/AppelloProtocolDecoder.java
index 47e329234..8e182b9fb 100644
--- a/src/main/java/org/traccar/protocol/AppelloProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AppelloProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/AquilaProtocol.java b/src/main/java/org/traccar/protocol/AquilaProtocol.java
index 5ca1ec091..bd9c34d08 100644
--- a/src/main/java/org/traccar/protocol/AquilaProtocol.java
+++ b/src/main/java/org/traccar/protocol/AquilaProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class AquilaProtocol extends BaseProtocol {
- public AquilaProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public AquilaProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/AquilaProtocolDecoder.java b/src/main/java/org/traccar/protocol/AquilaProtocolDecoder.java
index 3c43ddf2a..50ff10469 100644
--- a/src/main/java/org/traccar/protocol/AquilaProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AquilaProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/Ardi01Protocol.java b/src/main/java/org/traccar/protocol/Ardi01Protocol.java
index f7826430f..5ddbe9d62 100644
--- a/src/main/java/org/traccar/protocol/Ardi01Protocol.java
+++ b/src/main/java/org/traccar/protocol/Ardi01Protocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Ardi01Protocol extends BaseProtocol {
- public Ardi01Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Ardi01Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/Ardi01ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Ardi01ProtocolDecoder.java
index 85e9ecfde..07653623a 100644
--- a/src/main/java/org/traccar/protocol/Ardi01ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Ardi01ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/ArknavProtocol.java b/src/main/java/org/traccar/protocol/ArknavProtocol.java
index 3b485e4a5..20fec296c 100644
--- a/src/main/java/org/traccar/protocol/ArknavProtocol.java
+++ b/src/main/java/org/traccar/protocol/ArknavProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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.
@@ -21,19 +21,32 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class ArknavProtocol extends BaseProtocol {
- public ArknavProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public ArknavProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\r'));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new ArknavProtocolDecoder(ArknavProtocol.this));
}
});
+ addServer(new TrackerServer(config, getName(), true) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new StringDecoder());
+ pipeline.addLast(new StringEncoder());
+ pipeline.addLast(new ArknavProtocolDecoder(ArknavProtocol.this));
+ }
+ });
+
}
}
diff --git a/src/main/java/org/traccar/protocol/ArknavProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArknavProtocolDecoder.java
index 4982e02fc..4def9c979 100644
--- a/src/main/java/org/traccar/protocol/ArknavProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ArknavProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/ArknavX8Protocol.java b/src/main/java/org/traccar/protocol/ArknavX8Protocol.java
index a29bc1ad3..a8be6f40c 100644
--- a/src/main/java/org/traccar/protocol/ArknavX8Protocol.java
+++ b/src/main/java/org/traccar/protocol/ArknavX8Protocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class ArknavX8Protocol extends BaseProtocol {
- public ArknavX8Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public ArknavX8Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ';'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/ArknavX8ProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArknavX8ProtocolDecoder.java
index b570f5423..22c0344d6 100644
--- a/src/main/java/org/traccar/protocol/ArknavX8ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ArknavX8ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/ArmoliProtocol.java b/src/main/java/org/traccar/protocol/ArmoliProtocol.java
index 5f36012af..e9c947ecd 100644
--- a/src/main/java/org/traccar/protocol/ArmoliProtocol.java
+++ b/src/main/java/org/traccar/protocol/ArmoliProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class ArmoliProtocol extends BaseProtocol {
- public ArmoliProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public ArmoliProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ";;", ";\r", ";"));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/ArmoliProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArmoliProtocolDecoder.java
index 50af039d6..cbed64f76 100644
--- a/src/main/java/org/traccar/protocol/ArmoliProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ArmoliProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.ObdDecoder;
diff --git a/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java
index e957a6911..0f6b7a33f 100644
--- a/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ArnaviBinaryProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Checksum;
diff --git a/src/main/java/org/traccar/protocol/ArnaviProtocol.java b/src/main/java/org/traccar/protocol/ArnaviProtocol.java
index aecb42c8c..962bcce52 100644
--- a/src/main/java/org/traccar/protocol/ArnaviProtocol.java
+++ b/src/main/java/org/traccar/protocol/ArnaviProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class ArnaviProtocol extends BaseProtocol {
- public ArnaviProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public ArnaviProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new ArnaviFrameDecoder());
pipeline.addLast(new ArnaviProtocolDecoder(ArnaviProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java
index 68a70c944..50ceea898 100644
--- a/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ArnaviProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2020 - 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,11 +15,13 @@
*/
package org.traccar.protocol;
+import com.google.inject.Injector;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.Protocol;
+import jakarta.inject.Inject;
import java.net.SocketAddress;
public class ArnaviProtocolDecoder extends BaseProtocolDecoder {
@@ -33,6 +35,12 @@ public class ArnaviProtocolDecoder extends BaseProtocolDecoder {
binaryProtocolDecoder = new ArnaviBinaryProtocolDecoder(protocol);
}
+ @Inject
+ public void setInjector(Injector injector) {
+ injector.injectMembers(textProtocolDecoder);
+ injector.injectMembers(binaryProtocolDecoder);
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
diff --git a/src/main/java/org/traccar/protocol/ArnaviTextProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArnaviTextProtocolDecoder.java
index b99869e6e..9d82c9ad5 100644
--- a/src/main/java/org/traccar/protocol/ArnaviTextProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ArnaviTextProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/AstraProtocol.java b/src/main/java/org/traccar/protocol/AstraProtocol.java
index 12b0dfb68..dcc02d10d 100644
--- a/src/main/java/org/traccar/protocol/AstraProtocol.java
+++ b/src/main/java/org/traccar/protocol/AstraProtocol.java
@@ -19,20 +19,24 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class AstraProtocol extends BaseProtocol {
- public AstraProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public AstraProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 1, 2, -3, 0));
pipeline.addLast(new AstraProtocolDecoder(AstraProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new AstraProtocolDecoder(AstraProtocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/AstraProtocolDecoder.java b/src/main/java/org/traccar/protocol/AstraProtocolDecoder.java
index e6f546b9f..366bf9e8b 100644
--- a/src/main/java/org/traccar/protocol/AstraProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AstraProtocolDecoder.java
@@ -21,7 +21,7 @@ import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/At2000Protocol.java b/src/main/java/org/traccar/protocol/At2000Protocol.java
index 5894f3eab..c7e22f142 100644
--- a/src/main/java/org/traccar/protocol/At2000Protocol.java
+++ b/src/main/java/org/traccar/protocol/At2000Protocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class At2000Protocol extends BaseProtocol {
- public At2000Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public At2000Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new At2000FrameDecoder());
pipeline.addLast(new At2000ProtocolDecoder(At2000Protocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/At2000ProtocolDecoder.java b/src/main/java/org/traccar/protocol/At2000ProtocolDecoder.java
index 43798eb67..b81ba306d 100644
--- a/src/main/java/org/traccar/protocol/At2000ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/At2000ProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DataConverter;
diff --git a/src/main/java/org/traccar/protocol/AtrackProtocol.java b/src/main/java/org/traccar/protocol/AtrackProtocol.java
index 429708b26..8b86955f4 100644
--- a/src/main/java/org/traccar/protocol/AtrackProtocol.java
+++ b/src/main/java/org/traccar/protocol/AtrackProtocol.java
@@ -18,24 +18,28 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class AtrackProtocol extends BaseProtocol {
- public AtrackProtocol() {
+ @Inject
+ public AtrackProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new AtrackFrameDecoder());
pipeline.addLast(new AtrackProtocolEncoder(AtrackProtocol.this));
pipeline.addLast(new AtrackProtocolDecoder(AtrackProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new AtrackProtocolEncoder(AtrackProtocol.this));
pipeline.addLast(new AtrackProtocolDecoder(AtrackProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java
index 186b81470..8896dcfb0 100644
--- a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java
@@ -20,8 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.config.Keys;
@@ -54,7 +53,7 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
private static final int MIN_DATA_LENGTH = 40;
private boolean longDate;
- private final boolean decimalFuel;
+ private boolean decimalFuel;
private boolean custom;
private String form;
@@ -64,17 +63,20 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
public AtrackProtocolDecoder(Protocol protocol) {
super(protocol);
+ }
- longDate = Context.getConfig().getBoolean(Keys.PROTOCOL_LONG_DATE.withPrefix(getProtocolName()));
- decimalFuel = Context.getConfig().getBoolean(Keys.PROTOCOL_DECIMAL_FUEL.withPrefix(getProtocolName()));
+ @Override
+ protected void init() {
+ longDate = getConfig().getBoolean(Keys.PROTOCOL_LONG_DATE.withPrefix(getProtocolName()));
+ decimalFuel = getConfig().getBoolean(Keys.PROTOCOL_DECIMAL_FUEL.withPrefix(getProtocolName()));
- custom = Context.getConfig().getBoolean(Keys.PROTOCOL_CUSTOM.withPrefix(getProtocolName()));
- form = Context.getConfig().getString(Keys.PROTOCOL_FORM.withPrefix(getProtocolName()));
+ custom = getConfig().getBoolean(Keys.PROTOCOL_CUSTOM.withPrefix(getProtocolName()));
+ form = getConfig().getString(Keys.PROTOCOL_FORM.withPrefix(getProtocolName()));
if (form != null) {
custom = true;
}
- String alarmMapString = Context.getConfig().getString(Keys.PROTOCOL_ALARM_MAP.withPrefix(getProtocolName()));
+ String alarmMapString = getConfig().getString(Keys.PROTOCOL_ALARM_MAP.withPrefix(getProtocolName()));
if (alarmMapString != null) {
for (String pair : alarmMapString.split(",")) {
if (!pair.isEmpty()) {
@@ -98,7 +100,7 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
this.form = form;
}
- private static void sendResponse(Channel channel, SocketAddress remoteAddress, long rawId, int index) {
+ private void sendResponse(Channel channel, SocketAddress remoteAddress, long rawId, int index) {
if (channel != null) {
ByteBuf response = Unpooled.buffer(12);
response.writeShort(0xfe02);
@@ -427,6 +429,208 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
case "MP":
buf.readUnsignedByte(); // manifold absolute pressure
break;
+ case "EO":
+ position.set(Position.KEY_ODOMETER, UnitsConverter.metersFromMiles(buf.readUnsignedInt()));
+ break;
+ case "EH":
+ position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 360000);
+ break;
+ case "ZO1":
+ buf.readUnsignedByte(); // brake stroke status
+ break;
+ case "ZO2":
+ buf.readUnsignedByte(); // warning indicator status
+ break;
+ case "ZO3":
+ buf.readUnsignedByte(); // abs control status
+ break;
+ case "ZO4":
+ position.set(Position.KEY_THROTTLE, buf.readUnsignedByte() * 0.4);
+ break;
+ case "ZO5":
+ buf.readUnsignedByte(); // parking brake status
+ break;
+ case "ZO6":
+ position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte() * 0.805);
+ break;
+ case "ZO7":
+ buf.readUnsignedByte(); // cruise control status
+ break;
+ case "ZO8":
+ buf.readUnsignedByte(); // accelector pedal position
+ break;
+ case "ZO9":
+ position.set(Position.KEY_ENGINE_LOAD, buf.readUnsignedByte() * 0.5);
+ break;
+ case "ZO10":
+ position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.5);
+ break;
+ case "ZO11":
+ buf.readUnsignedByte(); // engine oil pressure
+ break;
+ case "ZO12":
+ buf.readUnsignedByte(); // boost pressure
+ break;
+ case "ZO13":
+ buf.readUnsignedByte(); // intake temperature
+ break;
+ case "ZO14":
+ position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte());
+ break;
+ case "ZO15":
+ buf.readUnsignedByte(); // brake application pressure
+ break;
+ case "ZO16":
+ buf.readUnsignedByte(); // brake primary pressure
+ break;
+ case "ZO17":
+ buf.readUnsignedByte(); // brake secondary pressure
+ break;
+ case "ZH1":
+ buf.readUnsignedShort(); // cargo weight
+ break;
+ case "ZH2":
+ position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 16.428 / 3600);
+ break;
+ case "ZH3":
+ position.set(Position.KEY_RPM, buf.readUnsignedShort() * 0.25);
+ break;
+ case "ZL1":
+ buf.readUnsignedInt(); // fuel used (natural gas)
+ break;
+ case "ZL2":
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 161);
+ break;
+ case "ZL3":
+ buf.readUnsignedInt(); // vehicle hours
+ break;
+ case "ZL4":
+ position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 5 * 36000);
+ break;
+ case "ZS1":
+ position.set(Position.KEY_VIN, readString(buf));
+ break;
+ case "JO1":
+ buf.readUnsignedByte(); // pedals
+ break;
+ case "JO2":
+ buf.readUnsignedByte(); // power takeoff device
+ break;
+ case "JO3":
+ buf.readUnsignedByte(); // accelector pedal position
+ break;
+ case "JO4":
+ position.set(Position.KEY_ENGINE_LOAD, buf.readUnsignedByte());
+ break;
+ case "JO5":
+ position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.4);
+ break;
+ case "JO6":
+ buf.readUnsignedByte(); // fms vehicle interface
+ break;
+ case "JO7":
+ buf.readUnsignedByte(); // driver 2
+ break;
+ case "JO8":
+ buf.readUnsignedByte(); // driver 1
+ break;
+ case "JO9":
+ buf.readUnsignedByte(); // drivers
+ break;
+ case "JO10":
+ buf.readUnsignedByte(); // system information
+ break;
+ case "JO11":
+ position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte() - 40);
+ break;
+ case "JO12":
+ buf.readUnsignedByte(); // pto engaged
+ break;
+ case "JH1":
+ position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() / 256.0);
+ break;
+ case "JH2":
+ position.set(Position.KEY_RPM, buf.readUnsignedShort() * 0.125);
+ break;
+ case "JH3":
+ case "JH4":
+ case "JH5":
+ case "JH6":
+ case "JH7":
+ int index = Integer.parseInt(key.substring(2)) - 2;
+ position.set("axleWeight" + index, buf.readUnsignedShort() * 0.5);
+ break;
+ case "JH8":
+ position.set(Position.KEY_ODOMETER_SERVICE, buf.readUnsignedShort() * 5);
+ break;
+ case "JH9":
+ buf.readUnsignedShort(); // tachograph speed
+ break;
+ case "JH10":
+ buf.readUnsignedShort(); // ambient air temperature
+ break;
+ case "JH11":
+ position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 0.05);
+ break;
+ case "JH12":
+ buf.readUnsignedShort(); // fuel economy
+ break;
+ case "JL1":
+ position.set(Position.KEY_FUEL_USED, buf.readUnsignedInt() * 0.5);
+ break;
+ case "JL2":
+ position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 5 * 36000);
+ break;
+ case "JL3":
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 1000);
+ break;
+ case "JL4":
+ position.set(Position.KEY_FUEL_USED, buf.readUnsignedInt() * 0.001);
+ break;
+ case "JS1":
+ position.set(Position.KEY_VIN, readString(buf));
+ break;
+ case "JS2":
+ readString(buf); // fms version supported
+ break;
+ case "JS3":
+ position.set("driver1", readString(buf));
+ break;
+ case "JS4":
+ position.set("driver2", readString(buf));
+ break;
+ case "JN1":
+ buf.readUnsignedInt(); // cruise control distance
+ break;
+ case "JN2":
+ buf.readUnsignedInt(); // excessive idling time
+ break;
+ case "JN3":
+ buf.readUnsignedInt(); // excessive idling fuel
+ break;
+ case "JN4":
+ buf.readUnsignedInt(); // pto time
+ break;
+ case "JN5":
+ buf.readUnsignedInt(); // pto fuel
+ break;
+ case "IN0":
+ position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0);
+ break;
+ case "IN1":
+ case "IN2":
+ case "IN3":
+ position.set(Position.PREFIX_IN + key.charAt(2), buf.readUnsignedByte() > 0);
+ break;
+ case "HA":
+ position.set(Position.KEY_ALARM, buf.readUnsignedByte() > 0 ? Position.ALARM_ACCELERATION : null);
+ break;
+ case "HB":
+ position.set(Position.KEY_ALARM, buf.readUnsignedByte() > 0 ? Position.ALARM_BRAKING : null);
+ break;
+ case "HC":
+ position.set(Position.KEY_ALARM, buf.readUnsignedByte() > 0 ? Position.ALARM_CORNERING : null);
+ break;
default:
break;
}
@@ -524,20 +728,24 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
private List<Position> decodeText(Channel channel, SocketAddress remoteAddress, String sentence) {
- int startIndex = -1;
- for (int i = 0; i < 4; i++) {
- startIndex = sentence.indexOf(',', startIndex + 1);
+ int positionIndex = -1;
+ for (int i = 0; i < 5; i++) {
+ positionIndex = sentence.indexOf(',', positionIndex + 1);
}
- int endIndex = sentence.indexOf(',', startIndex + 1);
- String imei = sentence.substring(startIndex + 1, endIndex);
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
+ String[] headers = sentence.substring(0, positionIndex).split(",");
+ long id = Long.parseLong(headers[2]);
+ int index = Integer.parseInt(headers[3]);
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, headers[4]);
if (deviceSession == null) {
return null;
}
+ sendResponse(channel, remoteAddress, id, index);
+
List<Position> positions = new LinkedList<>();
- String[] lines = sentence.substring(endIndex + 1).split("\r\n");
+ String[] lines = sentence.substring(positionIndex + 1).split("\r\n");
for (String line : lines) {
Position position = decodeTextLine(deviceSession, line);
@@ -626,7 +834,7 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
getLastLocation(position, new Date(time * 1000));
- position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(String.valueOf(id), photo, "jpg"));
+ position.set(Position.KEY_IMAGE, writeMediaFile(String.valueOf(id), photo, "jpg"));
photo.release();
photo = null;
diff --git a/src/main/java/org/traccar/protocol/AuroProtocol.java b/src/main/java/org/traccar/protocol/AuroProtocol.java
index b8ebdaa75..728c8e23c 100644
--- a/src/main/java/org/traccar/protocol/AuroProtocol.java
+++ b/src/main/java/org/traccar/protocol/AuroProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class AuroProtocol extends BaseProtocol {
- public AuroProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public AuroProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/AuroProtocolDecoder.java b/src/main/java/org/traccar/protocol/AuroProtocolDecoder.java
index d7916147b..4489cf27e 100644
--- a/src/main/java/org/traccar/protocol/AuroProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AuroProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/AustinNbProtocol.java b/src/main/java/org/traccar/protocol/AustinNbProtocol.java
index 32bfc0aae..467deff53 100644
--- a/src/main/java/org/traccar/protocol/AustinNbProtocol.java
+++ b/src/main/java/org/traccar/protocol/AustinNbProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class AustinNbProtocol extends BaseProtocol {
- public AustinNbProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public AustinNbProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new AustinNbProtocolDecoder(AustinNbProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/AustinNbProtocolDecoder.java b/src/main/java/org/traccar/protocol/AustinNbProtocolDecoder.java
index dc6f3d280..b07b94e20 100644
--- a/src/main/java/org/traccar/protocol/AustinNbProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AustinNbProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 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,14 +17,13 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
import org.traccar.model.Position;
import java.net.SocketAddress;
-import java.util.TimeZone;
import java.util.regex.Pattern;
public class AustinNbProtocolDecoder extends BaseProtocolDecoder {
@@ -64,7 +63,7 @@ public class AustinNbProtocolDecoder extends BaseProtocolDecoder {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
- position.setTime(parser.nextDateTime(Parser.DateTimeFormat.YMD_HMS, TimeZone.getDefault().getID()));
+ position.setTime(parser.nextDateTime());
position.setValid(true);
position.setLatitude(Double.parseDouble(parser.next().replace(',', '.')));
diff --git a/src/main/java/org/traccar/protocol/AutoFonProtocol.java b/src/main/java/org/traccar/protocol/AutoFonProtocol.java
index 08b5edc7d..75bd28d5e 100644
--- a/src/main/java/org/traccar/protocol/AutoFonProtocol.java
+++ b/src/main/java/org/traccar/protocol/AutoFonProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class AutoFonProtocol extends BaseProtocol {
- public AutoFonProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public AutoFonProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new AutoFonFrameDecoder());
pipeline.addLast(new AutoFonProtocolDecoder(AutoFonProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/AutoFonProtocolDecoder.java b/src/main/java/org/traccar/protocol/AutoFonProtocolDecoder.java
index aa05ca2d7..dd6a0e33c 100644
--- a/src/main/java/org/traccar/protocol/AutoFonProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AutoFonProtocolDecoder.java
@@ -21,7 +21,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/AutoGradeProtocol.java b/src/main/java/org/traccar/protocol/AutoGradeProtocol.java
index c6dbb681e..69d9fb4e6 100644
--- a/src/main/java/org/traccar/protocol/AutoGradeProtocol.java
+++ b/src/main/java/org/traccar/protocol/AutoGradeProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class AutoGradeProtocol extends BaseProtocol {
- public AutoGradeProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public AutoGradeProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ')'));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/AutoGradeProtocolDecoder.java b/src/main/java/org/traccar/protocol/AutoGradeProtocolDecoder.java
index 5052450b5..f52ac81c9 100644
--- a/src/main/java/org/traccar/protocol/AutoGradeProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AutoGradeProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/AutoTrackProtocol.java b/src/main/java/org/traccar/protocol/AutoTrackProtocol.java
index 6aa7558bf..df489de3c 100644
--- a/src/main/java/org/traccar/protocol/AutoTrackProtocol.java
+++ b/src/main/java/org/traccar/protocol/AutoTrackProtocol.java
@@ -19,14 +19,18 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import java.nio.ByteOrder;
+import jakarta.inject.Inject;
+
public class AutoTrackProtocol extends BaseProtocol {
- public AutoTrackProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public AutoTrackProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 5, 2, 2, 0, true));
pipeline.addLast(new AutoTrackProtocolDecoder(AutoTrackProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/AutoTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/AutoTrackProtocolDecoder.java
index da7f6b5a6..c072e55d0 100644
--- a/src/main/java/org/traccar/protocol/AutoTrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AutoTrackProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Checksum;
diff --git a/src/main/java/org/traccar/protocol/AvemaProtocol.java b/src/main/java/org/traccar/protocol/AvemaProtocol.java
index dbfab4dea..0eeee41b8 100644
--- a/src/main/java/org/traccar/protocol/AvemaProtocol.java
+++ b/src/main/java/org/traccar/protocol/AvemaProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class AvemaProtocol extends BaseProtocol {
- public AvemaProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public AvemaProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/AvemaProtocolDecoder.java b/src/main/java/org/traccar/protocol/AvemaProtocolDecoder.java
index 37836ad5f..0793975df 100644
--- a/src/main/java/org/traccar/protocol/AvemaProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AvemaProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/Avl301Protocol.java b/src/main/java/org/traccar/protocol/Avl301Protocol.java
index 71fc7cb26..452bc1501 100644
--- a/src/main/java/org/traccar/protocol/Avl301Protocol.java
+++ b/src/main/java/org/traccar/protocol/Avl301Protocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Avl301Protocol extends BaseProtocol {
- public Avl301Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Avl301Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 1, -3, 0));
pipeline.addLast(new Avl301ProtocolDecoder(Avl301Protocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/Avl301ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Avl301ProtocolDecoder.java
index f6b7db2d6..8f036fc29 100644
--- a/src/main/java/org/traccar/protocol/Avl301ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Avl301ProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
@@ -125,7 +125,7 @@ public class Avl301ProtocolDecoder extends BaseProtocolDecoder {
}
position.setNetwork(new Network(
- CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedMedium())));
+ CellTower.fromLacCid(getConfig(), buf.readUnsignedShort(), buf.readUnsignedMedium())));
position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
int flags = buf.readUnsignedByte();
diff --git a/src/main/java/org/traccar/protocol/B2316Protocol.java b/src/main/java/org/traccar/protocol/B2316Protocol.java
index 7f08870ce..e0a6821d8 100644
--- a/src/main/java/org/traccar/protocol/B2316Protocol.java
+++ b/src/main/java/org/traccar/protocol/B2316Protocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class B2316Protocol extends BaseProtocol {
- public B2316Protocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public B2316Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new B2316ProtocolDecoder(B2316Protocol.this));
diff --git a/src/main/java/org/traccar/protocol/B2316ProtocolDecoder.java b/src/main/java/org/traccar/protocol/B2316ProtocolDecoder.java
index 854107a20..b0a5411f7 100644
--- a/src/main/java/org/traccar/protocol/B2316ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/B2316ProtocolDecoder.java
@@ -17,16 +17,16 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.model.CellTower;
import org.traccar.model.Network;
import org.traccar.model.Position;
import org.traccar.model.WifiAccessPoint;
-import javax.json.Json;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
+import jakarta.json.Json;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
import java.io.StringReader;
import java.net.SocketAddress;
import java.util.Date;
@@ -116,8 +116,9 @@ public class B2316ProtocolDecoder extends BaseProtocolDecoder {
String[] points = item.getString("wi").split(";");
for (String point : points) {
String[] values = point.split(",");
+ String mac = values[0].replaceAll("(..)", "$1:");
network.addWifiAccessPoint(WifiAccessPoint.from(
- values[0].replaceAll("(..)", "$1:"), Integer.parseInt(values[1])));
+ mac.substring(0, mac.length() - 1), Integer.parseInt(values[1])));
}
}
diff --git a/src/main/java/org/traccar/protocol/BceProtocol.java b/src/main/java/org/traccar/protocol/BceProtocol.java
index c5e1dd04c..5e1c10abc 100644
--- a/src/main/java/org/traccar/protocol/BceProtocol.java
+++ b/src/main/java/org/traccar/protocol/BceProtocol.java
@@ -18,16 +18,20 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class BceProtocol extends BaseProtocol {
- public BceProtocol() {
+ @Inject
+ public BceProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_OUTPUT_CONTROL);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new BceFrameDecoder());
pipeline.addLast(new BceProtocolEncoder(BceProtocol.this));
pipeline.addLast(new BceProtocolDecoder(BceProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java
index 535827f3c..2c9459584 100644
--- a/src/main/java/org/traccar/protocol/BceProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/BceProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/BlackKiteProtocol.java b/src/main/java/org/traccar/protocol/BlackKiteProtocol.java
index 617a24d7a..d584af5a1 100644
--- a/src/main/java/org/traccar/protocol/BlackKiteProtocol.java
+++ b/src/main/java/org/traccar/protocol/BlackKiteProtocol.java
@@ -19,13 +19,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class BlackKiteProtocol extends BaseProtocol {
- public BlackKiteProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public BlackKiteProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new GalileoFrameDecoder());
pipeline.addLast(new BlackKiteProtocolDecoder(BlackKiteProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/BlackKiteProtocolDecoder.java b/src/main/java/org/traccar/protocol/BlackKiteProtocolDecoder.java
index 474ceabdc..64fc439c4 100644
--- a/src/main/java/org/traccar/protocol/BlackKiteProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/BlackKiteProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/BlueProtocol.java b/src/main/java/org/traccar/protocol/BlueProtocol.java
index d5dc5c421..821111ad7 100644
--- a/src/main/java/org/traccar/protocol/BlueProtocol.java
+++ b/src/main/java/org/traccar/protocol/BlueProtocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class BlueProtocol extends BaseProtocol {
- public BlueProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public BlueProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 1, 2, -2, 0));
pipeline.addLast(new BlueProtocolDecoder(BlueProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/BlueProtocolDecoder.java b/src/main/java/org/traccar/protocol/BlueProtocolDecoder.java
index f35ac6fbe..db59c564d 100644
--- a/src/main/java/org/traccar/protocol/BlueProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/BlueProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/BoxProtocol.java b/src/main/java/org/traccar/protocol/BoxProtocol.java
index dfea15938..ac1ba7cae 100644
--- a/src/main/java/org/traccar/protocol/BoxProtocol.java
+++ b/src/main/java/org/traccar/protocol/BoxProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class BoxProtocol extends BaseProtocol {
- public BoxProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public BoxProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\r'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/BoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/BoxProtocolDecoder.java
index 853fa8f81..8e92b69fb 100644
--- a/src/main/java/org/traccar/protocol/BoxProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/BoxProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/BstplProtocol.java b/src/main/java/org/traccar/protocol/BstplProtocol.java
new file mode 100644
index 000000000..ccedcf3d9
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/BstplProtocol.java
@@ -0,0 +1,43 @@
+/*
+ * 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.protocol;
+
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.CharacterDelimiterFrameDecoder;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
+
+public class BstplProtocol extends BaseProtocol {
+
+ @Inject
+ public BstplProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#'));
+ pipeline.addLast(new StringEncoder());
+ pipeline.addLast(new StringDecoder());
+ pipeline.addLast(new BstplProtocolDecoder(BstplProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/BstplProtocolDecoder.java b/src/main/java/org/traccar/protocol/BstplProtocolDecoder.java
new file mode 100644
index 000000000..15c114642
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/BstplProtocolDecoder.java
@@ -0,0 +1,137 @@
+/*
+ * 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.protocol;
+
+import io.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.Protocol;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+import org.traccar.session.DeviceSession;
+
+import java.net.SocketAddress;
+import java.util.regex.Pattern;
+
+public class BstplProtocolDecoder extends BaseProtocolDecoder {
+
+ public BstplProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("BSTPL$") // header
+ .number("(d),") // type
+ .expression("([^,]+),") // device id
+ .expression("([AV]),") // validity
+ .number("(dd)(dd)(dd),") // date (ddmmyy)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .number("(d+.d+),([0NS]),") // latitude
+ .number("(d+.d+),([0EW]),") // longitude
+ .number("(d+),") // speed
+ .number("(d+),") // odometer
+ .number("(d+),") // course
+ .number("(d+),") // satellites
+ .number("([01]),") // box open
+ .number("(d+),") // rssi
+ .number("([01]),") // charge
+ .number("([01]),") // ignition
+ .number("([01]),") // engine
+ .number("([01]),") // locked
+ .number("(d+.d+),") // adc
+ .number("d+,") // reserved
+ .number("(d+.d+),") // battery
+ .expression("([^,]+),") // firmware
+ .number("([^,]+),") // iccid
+ .number("(d+.d+)") // power
+ .compile();
+
+ private String decodeAlarm(int value) {
+ switch (value) {
+ case 4:
+ return Position.ALARM_LOW_BATTERY;
+ case 5:
+ return Position.ALARM_ACCELERATION;
+ case 6:
+ return Position.ALARM_BRAKING;
+ case 7:
+ return Position.ALARM_OVERSPEED;
+ case 9:
+ return Position.ALARM_SOS;
+ default:
+ return null;
+ }
+ }
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ Parser parser = new Parser(PATTERN, (String) msg);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ int type = parser.nextInt();
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.set(Position.KEY_ALARM, decodeAlarm(type));
+
+ position.setValid(parser.next().equals("A"));
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt()));
+
+ position.set(Position.KEY_ODOMETER, parser.nextInt() * 1000L);
+
+ position.setCourse(parser.nextInt());
+
+ position.set(Position.KEY_SATELLITES, parser.nextInt());
+
+ boolean boxOpen = parser.nextInt() > 0;
+ if (type == 8 && boxOpen) {
+ position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING);
+ }
+ position.set("boxOpen", boxOpen);
+
+ position.set(Position.KEY_RSSI, parser.nextInt());
+
+ boolean charge = parser.nextInt() > 0;
+ if (type == 3) {
+ position.set(Position.KEY_ALARM, charge ? Position.ALARM_POWER_RESTORED : Position.ALARM_POWER_CUT);
+ }
+ position.set(Position.KEY_CHARGE, charge);
+
+ position.set(Position.KEY_IGNITION, parser.nextInt() > 0);
+ position.set("engine", parser.nextInt() > 0);
+ position.set(Position.KEY_BLOCKED, parser.nextInt() > 0);
+ position.set(Position.PREFIX_ADC + 1, parser.nextDouble());
+ position.set(Position.KEY_BATTERY, parser.nextDouble());
+ position.set(Position.KEY_ICCID, parser.next());
+ position.set(Position.KEY_POWER, parser.nextDouble());
+
+ return position;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/C2stekProtocol.java b/src/main/java/org/traccar/protocol/C2stekProtocol.java
index 804621fd3..5370ea762 100644
--- a/src/main/java/org/traccar/protocol/C2stekProtocol.java
+++ b/src/main/java/org/traccar/protocol/C2stekProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class C2stekProtocol extends BaseProtocol {
- public C2stekProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public C2stekProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, false, "$AP"));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/C2stekProtocolDecoder.java b/src/main/java/org/traccar/protocol/C2stekProtocolDecoder.java
index e735c67a1..aef158fc7 100644
--- a/src/main/java/org/traccar/protocol/C2stekProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/C2stekProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
@@ -49,10 +49,12 @@ public class C2stekProtocolDecoder extends BaseProtocolDecoder {
.number("(-?d+.d+)#") // altitude
.number("(d+)#") // battery
.number("d+#") // geo area alarm
- .number("(x+)#") // alarm
- .number("([01])?") // armed
+ .number("(x+)") // alarm
+ .groupBegin()
+ .number("#([01])?") // armed
.number("([01])") // door
.number("([01])#") // ignition
+ .groupEnd("?")
.any()
.text("$AP")
.compile();
@@ -114,8 +116,10 @@ public class C2stekProtocolDecoder extends BaseProtocolDecoder {
if (parser.hasNext()) {
position.set(Position.KEY_ARMED, parser.nextInt() > 0);
}
- position.set(Position.KEY_DOOR, parser.nextInt() > 0);
- position.set(Position.KEY_IGNITION, parser.nextInt() > 0);
+ if (parser.hasNext(2)) {
+ position.set(Position.KEY_DOOR, parser.nextInt() > 0);
+ position.set(Position.KEY_IGNITION, parser.nextInt() > 0);
+ }
return position;
}
diff --git a/src/main/java/org/traccar/protocol/CalAmpProtocol.java b/src/main/java/org/traccar/protocol/CalAmpProtocol.java
index 232e72a8c..06df6e196 100644
--- a/src/main/java/org/traccar/protocol/CalAmpProtocol.java
+++ b/src/main/java/org/traccar/protocol/CalAmpProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class CalAmpProtocol extends BaseProtocol {
- public CalAmpProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public CalAmpProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CalAmpProtocolDecoder(CalAmpProtocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/CalAmpProtocolDecoder.java b/src/main/java/org/traccar/protocol/CalAmpProtocolDecoder.java
index 59b1fdf21..57f9c69ae 100644
--- a/src/main/java/org/traccar/protocol/CalAmpProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/CalAmpProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/CarTrackProtocol.java b/src/main/java/org/traccar/protocol/CarTrackProtocol.java
index e340fba25..366f32034 100644
--- a/src/main/java/org/traccar/protocol/CarTrackProtocol.java
+++ b/src/main/java/org/traccar/protocol/CarTrackProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class CarTrackProtocol extends BaseProtocol {
- public CarTrackProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public CarTrackProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "##"));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/CarTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/CarTrackProtocolDecoder.java
index ce3345826..3f5418549 100644
--- a/src/main/java/org/traccar/protocol/CarTrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/CarTrackProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/CarcellProtocol.java b/src/main/java/org/traccar/protocol/CarcellProtocol.java
index f08ab3bd9..7ae8159d5 100644
--- a/src/main/java/org/traccar/protocol/CarcellProtocol.java
+++ b/src/main/java/org/traccar/protocol/CarcellProtocol.java
@@ -21,17 +21,21 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class CarcellProtocol extends BaseProtocol {
- public CarcellProtocol() {
+ @Inject
+ public CarcellProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\r'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/CarcellProtocolDecoder.java b/src/main/java/org/traccar/protocol/CarcellProtocolDecoder.java
index ec640ba71..54ae068fb 100644
--- a/src/main/java/org/traccar/protocol/CarcellProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/CarcellProtocolDecoder.java
@@ -20,7 +20,7 @@ import java.util.regex.Pattern;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.Parser.CoordinateFormat;
diff --git a/src/main/java/org/traccar/protocol/CarscopProtocol.java b/src/main/java/org/traccar/protocol/CarscopProtocol.java
index 2c754a97f..e904c01c5 100644
--- a/src/main/java/org/traccar/protocol/CarscopProtocol.java
+++ b/src/main/java/org/traccar/protocol/CarscopProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class CarscopProtocol extends BaseProtocol {
- public CarscopProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public CarscopProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '^'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/CarscopProtocolDecoder.java b/src/main/java/org/traccar/protocol/CarscopProtocolDecoder.java
index 161666adc..f13a1d0eb 100644
--- a/src/main/java/org/traccar/protocol/CarscopProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/CarscopProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/CastelProtocol.java b/src/main/java/org/traccar/protocol/CastelProtocol.java
index 44c52d68f..74a9e9ca1 100644
--- a/src/main/java/org/traccar/protocol/CastelProtocol.java
+++ b/src/main/java/org/traccar/protocol/CastelProtocol.java
@@ -19,26 +19,30 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
import java.nio.ByteOrder;
+import jakarta.inject.Inject;
+
public class CastelProtocol extends BaseProtocol {
- public CastelProtocol() {
+ @Inject
+ public CastelProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, -4, 0, true));
pipeline.addLast(new CastelProtocolEncoder(CastelProtocol.this));
pipeline.addLast(new CastelProtocolDecoder(CastelProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CastelProtocolEncoder(CastelProtocol.this));
pipeline.addLast(new CastelProtocolDecoder(CastelProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java
index 23401b5ee..566d856bb 100644
--- a/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java
@@ -16,11 +16,10 @@
package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -160,6 +159,9 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder {
for (int i = 0; i < count; i++) {
int value;
+ if (!PID_LENGTH_MAP.containsKey(pids[i])) {
+ throw new RuntimeException(String.format("Unknown PID 0x%02x", pids[i]));
+ }
switch (PID_LENGTH_MAP.get(pids[i])) {
case 1:
value = buf.readUnsignedByte();
@@ -281,15 +283,27 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder {
case 0x0C:
position.set(Position.KEY_ALARM, Position.ALARM_CORNERING);
break;
+ case 0x0D:
+ position.set(Position.KEY_ALARM, Position.ALARM_FATIGUE_DRIVING);
+ break;
case 0x0E:
position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF);
break;
+ case 0x11:
+ position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT);
+ break;
+ case 0x12:
+ position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING);
+ break;
case 0x16:
position.set(Position.KEY_IGNITION, true);
break;
case 0x17:
position.set(Position.KEY_IGNITION, false);
break;
+ case 0x1C:
+ position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION);
+ break;
default:
break;
}
@@ -356,9 +370,9 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder {
int alarmCount = buf.readUnsignedByte();
for (int i = 0; i < alarmCount; i++) {
if (buf.readUnsignedByte() != 0) {
- int alarm = buf.readUnsignedByte();
+ int event = buf.readUnsignedByte();
for (Position p : positions) {
- decodeAlarm(p, alarm);
+ decodeAlarm(p, event);
}
buf.readUnsignedShortLE(); // description
buf.readUnsignedShortLE(); // threshold
@@ -418,12 +432,25 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder {
return position;
case MSG_SC_DTCS_PASSENGER:
+ case MSG_SC_DTCS_COMMERCIAL:
position = createPosition(deviceSession);
decodeStat(position, buf);
buf.readUnsignedByte(); // flag
- position.add(ObdDecoder.decodeCodes(ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte()))));
+
+ count = buf.readUnsignedByte();
+ StringBuilder codes = new StringBuilder();
+ for (int i = 0; i < count; i++) {
+ if (type == MSG_SC_DTCS_COMMERCIAL) {
+ codes.append(ObdDecoder.decodeCode(buf.readUnsignedShortLE()));
+ buf.readUnsignedByte(); // attribute
+ buf.readUnsignedByte(); // occurrence
+ } else {
+ codes.append(ObdDecoder.decodeCode(buf.readUnsignedShortLE()));
+ }
+ }
+ position.set(Position.KEY_DTCS, codes.toString().trim());
return position;
@@ -443,7 +470,7 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder {
decodeStat(position, buf);
position.setNetwork(new Network(
- CellTower.fromLacCid(buf.readUnsignedShortLE(), buf.readUnsignedShortLE())));
+ CellTower.fromLacCid(getConfig(), buf.readUnsignedShortLE(), buf.readUnsignedShortLE())));
return position;
@@ -499,7 +526,7 @@ public class CastelProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedByte(); // additional flags
position.setNetwork(new Network(
- CellTower.fromLacCid(buf.readUnsignedShortLE(), buf.readUnsignedShortLE())));
+ CellTower.fromLacCid(getConfig(), buf.readUnsignedShortLE(), buf.readUnsignedShortLE())));
positions.add(position);
}
diff --git a/src/main/java/org/traccar/protocol/CastelProtocolEncoder.java b/src/main/java/org/traccar/protocol/CastelProtocolEncoder.java
index dc694da28..61dde3e80 100644
--- a/src/main/java/org/traccar/protocol/CastelProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/CastelProtocolEncoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 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.
@@ -18,10 +18,9 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.traccar.BaseProtocolEncoder;
-import org.traccar.Context;
+import org.traccar.Protocol;
import org.traccar.helper.Checksum;
import org.traccar.model.Command;
-import org.traccar.Protocol;
import java.nio.charset.StandardCharsets;
@@ -34,7 +33,7 @@ public class CastelProtocolEncoder extends BaseProtocolEncoder {
private ByteBuf encodeContent(long deviceId, short type, ByteBuf content) {
ByteBuf buf = Unpooled.buffer(0);
- String uniqueId = Context.getIdentityManager().getById(deviceId).getUniqueId();
+ String uniqueId = getUniqueId(deviceId);
buf.writeByte('@');
buf.writeByte('@');
diff --git a/src/main/java/org/traccar/protocol/CautelaProtocol.java b/src/main/java/org/traccar/protocol/CautelaProtocol.java
index 452bdf8d4..067345f49 100644
--- a/src/main/java/org/traccar/protocol/CautelaProtocol.java
+++ b/src/main/java/org/traccar/protocol/CautelaProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class CautelaProtocol extends BaseProtocol {
- public CautelaProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public CautelaProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/CautelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/CautelaProtocolDecoder.java
index bddf19b41..37f733ac1 100644
--- a/src/main/java/org/traccar/protocol/CautelaProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/CautelaProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/CellocatorProtocol.java b/src/main/java/org/traccar/protocol/CellocatorProtocol.java
index d910877cf..e3325c8b7 100644
--- a/src/main/java/org/traccar/protocol/CellocatorProtocol.java
+++ b/src/main/java/org/traccar/protocol/CellocatorProtocol.java
@@ -18,24 +18,28 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class CellocatorProtocol extends BaseProtocol {
- public CellocatorProtocol() {
+ @Inject
+ public CellocatorProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_OUTPUT_CONTROL);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CellocatorFrameDecoder());
pipeline.addLast(new CellocatorProtocolEncoder(CellocatorProtocol.this));
pipeline.addLast(new CellocatorProtocolDecoder(CellocatorProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CellocatorProtocolEncoder(CellocatorProtocol.this));
pipeline.addLast(new CellocatorProtocolDecoder(CellocatorProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java
index 09bd3572f..3573a95ca 100644
--- a/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/CellocatorProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 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.
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -120,13 +120,15 @@ public class CellocatorProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedByte(); // operator / configuration flags
buf.readUnsignedByte(); // reason data
- position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
+ short event = buf.readUnsignedByte();
+ position.set(Position.KEY_ALARM, decodeAlarm(event));
+ position.set(Position.KEY_EVENT, event);
position.set("mode", buf.readUnsignedByte());
- long input = buf.readUnsignedIntLE();
+ long input = buf.readUnsignedInt();
+ position.set(Position.KEY_IGNITION, BitUtil.check(input, 3 * 8 + 5));
position.set(Position.KEY_DOOR, BitUtil.check(input, 3 * 8));
- position.set(Position.KEY_IGNITION, BitUtil.check(input, 2 * 8 + 7));
position.set(Position.KEY_CHARGE, BitUtil.check(input, 7));
position.set(Position.KEY_INPUT, input);
diff --git a/src/main/java/org/traccar/protocol/CguardProtocol.java b/src/main/java/org/traccar/protocol/CguardProtocol.java
index 9157ca35c..c0fc9582a 100644
--- a/src/main/java/org/traccar/protocol/CguardProtocol.java
+++ b/src/main/java/org/traccar/protocol/CguardProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class CguardProtocol extends BaseProtocol {
- public CguardProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public CguardProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/CguardProtocolDecoder.java b/src/main/java/org/traccar/protocol/CguardProtocolDecoder.java
index d934921f1..90f8e0caf 100644
--- a/src/main/java/org/traccar/protocol/CguardProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/CguardProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/CityeasyProtocol.java b/src/main/java/org/traccar/protocol/CityeasyProtocol.java
index 8ab4ce93a..60ed5d135 100644
--- a/src/main/java/org/traccar/protocol/CityeasyProtocol.java
+++ b/src/main/java/org/traccar/protocol/CityeasyProtocol.java
@@ -19,19 +19,23 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class CityeasyProtocol extends BaseProtocol {
- public CityeasyProtocol() {
+ @Inject
+ public CityeasyProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_POSITION_SINGLE,
Command.TYPE_POSITION_PERIODIC,
Command.TYPE_POSITION_STOP,
Command.TYPE_SET_TIMEZONE);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 2, -4, 0));
pipeline.addLast(new CityeasyProtocolEncoder(CityeasyProtocol.this));
pipeline.addLast(new CityeasyProtocolDecoder(CityeasyProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/CityeasyProtocolDecoder.java b/src/main/java/org/traccar/protocol/CityeasyProtocolDecoder.java
index 9c4c7e11d..1b5eb55d4 100644
--- a/src/main/java/org/traccar/protocol/CityeasyProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/CityeasyProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Checksum;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/ContinentalProtocol.java b/src/main/java/org/traccar/protocol/ContinentalProtocol.java
index bc7928fba..9567374fd 100644
--- a/src/main/java/org/traccar/protocol/ContinentalProtocol.java
+++ b/src/main/java/org/traccar/protocol/ContinentalProtocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class ContinentalProtocol extends BaseProtocol {
- public ContinentalProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public ContinentalProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 2, -4, 0));
pipeline.addLast(new ContinentalProtocolDecoder(ContinentalProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/ContinentalProtocolDecoder.java b/src/main/java/org/traccar/protocol/ContinentalProtocolDecoder.java
index 471afa0d6..280871e1e 100644
--- a/src/main/java/org/traccar/protocol/ContinentalProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ContinentalProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.UnitsConverter;
diff --git a/src/main/java/org/traccar/protocol/CradlepointProtocol.java b/src/main/java/org/traccar/protocol/CradlepointProtocol.java
index 4a09e0311..220db0747 100644
--- a/src/main/java/org/traccar/protocol/CradlepointProtocol.java
+++ b/src/main/java/org/traccar/protocol/CradlepointProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class CradlepointProtocol extends BaseProtocol {
- public CradlepointProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public CradlepointProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/CradlepointProtocolDecoder.java b/src/main/java/org/traccar/protocol/CradlepointProtocolDecoder.java
index a282131ce..924603291 100644
--- a/src/main/java/org/traccar/protocol/CradlepointProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/CradlepointProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/DingtekProtocol.java b/src/main/java/org/traccar/protocol/DingtekProtocol.java
index cf2a6c0f5..ab3e32fdb 100644
--- a/src/main/java/org/traccar/protocol/DingtekProtocol.java
+++ b/src/main/java/org/traccar/protocol/DingtekProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class DingtekProtocol extends BaseProtocol {
- public DingtekProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public DingtekProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new DingtekFrameDecoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/DingtekProtocolDecoder.java b/src/main/java/org/traccar/protocol/DingtekProtocolDecoder.java
index 98fe4b7b3..580741ec9 100644
--- a/src/main/java/org/traccar/protocol/DingtekProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/DingtekProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DataConverter;
import org.traccar.model.Position;
diff --git a/src/main/java/org/traccar/protocol/DishaProtocol.java b/src/main/java/org/traccar/protocol/DishaProtocol.java
index 38f49cc05..0a582731d 100644
--- a/src/main/java/org/traccar/protocol/DishaProtocol.java
+++ b/src/main/java/org/traccar/protocol/DishaProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class DishaProtocol extends BaseProtocol {
- public DishaProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public DishaProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/DishaProtocolDecoder.java b/src/main/java/org/traccar/protocol/DishaProtocolDecoder.java
index 3223988ab..1327e7a6c 100644
--- a/src/main/java/org/traccar/protocol/DishaProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/DishaProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/DmtHttpProtocol.java b/src/main/java/org/traccar/protocol/DmtHttpProtocol.java
index 34568128f..d15bfa1ca 100644
--- a/src/main/java/org/traccar/protocol/DmtHttpProtocol.java
+++ b/src/main/java/org/traccar/protocol/DmtHttpProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class DmtHttpProtocol extends BaseProtocol {
- public DmtHttpProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public DmtHttpProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(65535));
diff --git a/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java b/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java
index 815cce987..c2e617a2a 100644
--- a/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java
@@ -19,15 +19,15 @@ import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
-import javax.json.Json;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
+import jakarta.json.Json;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
import java.io.StringReader;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
diff --git a/src/main/java/org/traccar/protocol/DmtProtocol.java b/src/main/java/org/traccar/protocol/DmtProtocol.java
index 78a5243c0..e89920cd3 100644
--- a/src/main/java/org/traccar/protocol/DmtProtocol.java
+++ b/src/main/java/org/traccar/protocol/DmtProtocol.java
@@ -19,14 +19,18 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import java.nio.ByteOrder;
+import jakarta.inject.Inject;
+
public class DmtProtocol extends BaseProtocol {
- public DmtProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public DmtProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 3, 2, 0, 0, true));
pipeline.addLast(new DmtProtocolDecoder(DmtProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java b/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java
index 96b06557a..320aa1b60 100644
--- a/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/DmtProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -184,9 +184,9 @@ public class DmtProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_IGNITION, BitUtil.check(input, 0));
- if (!BitUtil.check(input, 1)) {
+ if (!BitUtil.check(status, 1)) {
position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY);
- } else if (BitUtil.check(input, 6)) {
+ } else if (BitUtil.check(status, 6)) {
position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING);
}
diff --git a/src/main/java/org/traccar/protocol/DolphinProtocol.java b/src/main/java/org/traccar/protocol/DolphinProtocol.java
index 07c827e18..e2acce7dd 100644
--- a/src/main/java/org/traccar/protocol/DolphinProtocol.java
+++ b/src/main/java/org/traccar/protocol/DolphinProtocol.java
@@ -19,15 +19,19 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import java.nio.ByteOrder;
+import jakarta.inject.Inject;
+
public class DolphinProtocol extends BaseProtocol {
- public DolphinProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public DolphinProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 4096, 20, 4, 4, 0, true));
pipeline.addLast(new DolphinProtocolDecoder(DolphinProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/DolphinProtocolDecoder.java b/src/main/java/org/traccar/protocol/DolphinProtocolDecoder.java
index d509b3ec0..b43635a52 100644
--- a/src/main/java/org/traccar/protocol/DolphinProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/DolphinProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.UnitsConverter;
diff --git a/src/main/java/org/traccar/protocol/Dsf22Protocol.java b/src/main/java/org/traccar/protocol/Dsf22Protocol.java
index bffc3e419..ad349a7ff 100644
--- a/src/main/java/org/traccar/protocol/Dsf22Protocol.java
+++ b/src/main/java/org/traccar/protocol/Dsf22Protocol.java
@@ -18,20 +18,24 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Dsf22Protocol extends BaseProtocol {
- public Dsf22Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Dsf22Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new Dsf22FrameDecoder());
pipeline.addLast(new Dsf22ProtocolDecoder(Dsf22Protocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new Dsf22ProtocolDecoder(Dsf22Protocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/Dsf22ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Dsf22ProtocolDecoder.java
index 3ef960f12..124bbfefa 100644
--- a/src/main/java/org/traccar/protocol/Dsf22ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Dsf22ProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/DualcamProtocol.java b/src/main/java/org/traccar/protocol/DualcamProtocol.java
index 04c4f2bd1..4725cb180 100644
--- a/src/main/java/org/traccar/protocol/DualcamProtocol.java
+++ b/src/main/java/org/traccar/protocol/DualcamProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class DualcamProtocol extends BaseProtocol {
- public DualcamProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public DualcamProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new DualcamFrameDecoder());
pipeline.addLast(new DualcamProtocolDecoder(DualcamProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java
index c64b8171f..d03f7648d 100644
--- a/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/DualcamProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2021 - 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.
@@ -19,8 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -47,7 +46,8 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder {
private String uniqueId;
private int packetCount;
private int currentPacket;
- private ByteBuf photo;
+ private boolean video;
+ private ByteBuf media;
@Override
protected Object decode(
@@ -65,13 +65,26 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder {
long settings = buf.readUnsignedInt();
if (channel != null && deviceSession != null) {
ByteBuf response = Unpooled.buffer();
- if (BitUtil.between(settings, 26, 28) > 0) {
+ if (BitUtil.between(settings, 26, 30) > 0) {
response.writeShort(MSG_FILE_REQUEST);
- String file = BitUtil.check(settings, 26) ? "%photof" : "%photor";
+ String file;
+ if (BitUtil.check(settings, 26)) {
+ video = false;
+ file = "%photof";
+ } else if (BitUtil.check(settings, 27)) {
+ video = false;
+ file = "%photor";
+ } else if (BitUtil.check(settings, 28)) {
+ video = true;
+ file = "%videof";
+ } else {
+ video = true;
+ file = "%videor";
+ }
response.writeShort(file.length());
response.writeCharSequence(file, StandardCharsets.US_ASCII);
} else {
- response.writeShort(MSG_COMPLETE);
+ response.writeShort(MSG_INIT);
}
channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
}
@@ -80,7 +93,7 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedShort(); // length
packetCount = buf.readInt();
currentPacket = 1;
- photo = Unpooled.buffer();
+ media = Unpooled.buffer();
if (channel != null) {
ByteBuf response = Unpooled.buffer();
response.writeShort(MSG_RESUME);
@@ -91,17 +104,21 @@ public class DualcamProtocolDecoder extends BaseProtocolDecoder {
break;
case MSG_DATA:
buf.readUnsignedShort(); // length
- photo.writeBytes(buf, buf.readableBytes() - 2);
+ media.writeBytes(buf, buf.readableBytes() - 2);
if (currentPacket == packetCount) {
deviceSession = getDeviceSession(channel, remoteAddress);
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
getLastLocation(position, null);
try {
- position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(uniqueId, photo, "jpg"));
+ if (video) {
+ position.set(Position.KEY_VIDEO, writeMediaFile(uniqueId, media, "h265"));
+ } else {
+ position.set(Position.KEY_IMAGE, writeMediaFile(uniqueId, media, "jpg"));
+ }
} finally {
- photo.release();
- photo = null;
+ media.release();
+ media = null;
}
if (channel != null) {
ByteBuf response = Unpooled.buffer();
diff --git a/src/main/java/org/traccar/protocol/DwayProtocol.java b/src/main/java/org/traccar/protocol/DwayProtocol.java
index 05fd8b6e7..2ba1cf5f1 100644
--- a/src/main/java/org/traccar/protocol/DwayProtocol.java
+++ b/src/main/java/org/traccar/protocol/DwayProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class DwayProtocol extends BaseProtocol {
- public DwayProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public DwayProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/DwayProtocolDecoder.java b/src/main/java/org/traccar/protocol/DwayProtocolDecoder.java
index 9b02c898e..9cf40b011 100644
--- a/src/main/java/org/traccar/protocol/DwayProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/DwayProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/EasyTrackProtocol.java b/src/main/java/org/traccar/protocol/EasyTrackProtocol.java
index 972b36077..25d4ef9a0 100644
--- a/src/main/java/org/traccar/protocol/EasyTrackProtocol.java
+++ b/src/main/java/org/traccar/protocol/EasyTrackProtocol.java
@@ -21,19 +21,23 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class EasyTrackProtocol extends BaseProtocol {
- public EasyTrackProtocol() {
+ @Inject
+ public EasyTrackProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME,
Command.TYPE_ALARM_ARM,
Command.TYPE_ALARM_DISARM);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "#\r\n", "#", "\r\n"));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java
index 4fcc48944..805cf1197 100644
--- a/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/EelinkProtocol.java b/src/main/java/org/traccar/protocol/EelinkProtocol.java
index 8a055d643..2a3c0bd15 100644
--- a/src/main/java/org/traccar/protocol/EelinkProtocol.java
+++ b/src/main/java/org/traccar/protocol/EelinkProtocol.java
@@ -19,28 +19,32 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class EelinkProtocol extends BaseProtocol {
- public EelinkProtocol() {
+ @Inject
+ public EelinkProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_POSITION_SINGLE,
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME,
Command.TYPE_REBOOT_DEVICE);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2));
pipeline.addLast(new EelinkProtocolEncoder(EelinkProtocol.this, false));
pipeline.addLast(new EelinkProtocolDecoder(EelinkProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new EelinkProtocolEncoder(EelinkProtocol.this, true));
pipeline.addLast(new EelinkProtocolDecoder(EelinkProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java
index 592e5a56c..db1b365c3 100644
--- a/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java
@@ -21,7 +21,7 @@ import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.socket.DatagramChannel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -273,6 +273,17 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
if (BitUtil.check(status, 1)) {
position.set(Position.KEY_IGNITION, BitUtil.check(status, 2));
}
+ if (BitUtil.check(status, 3)) {
+ position.set(Position.KEY_ARMED, BitUtil.check(status, 4));
+ position.set(Position.KEY_MOTION, BitUtil.check(status, 9));
+ }
+ if (BitUtil.check(status, 5)) {
+ position.set(Position.KEY_BLOCKED, BitUtil.check(status, 6));
+ }
+ if (BitUtil.check(status, 7)) {
+ position.set(Position.KEY_CHARGE, BitUtil.check(status, 8));
+ }
+ position.set(Position.KEY_GPS, BitUtil.check(status, 10));
position.set(Position.KEY_STATUS, status);
}
@@ -303,7 +314,7 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
}
if (buf.readableBytes() >= 12) {
- position.set(Position.PREFIX_TEMP + 1, buf.readUnsignedShort() / 256.0);
+ position.set(Position.PREFIX_TEMP + 1, buf.readShort() / 256.0);
position.set("humidity", buf.readUnsignedShort() * 0.1);
position.set("illuminance", buf.readUnsignedInt() / 256.0);
position.set("co2", buf.readUnsignedInt());
diff --git a/src/main/java/org/traccar/protocol/EgtsProtocol.java b/src/main/java/org/traccar/protocol/EgtsProtocol.java
index 5d4638f37..5450d9f01 100644
--- a/src/main/java/org/traccar/protocol/EgtsProtocol.java
+++ b/src/main/java/org/traccar/protocol/EgtsProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class EgtsProtocol extends BaseProtocol {
- public EgtsProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public EgtsProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new EgtsFrameDecoder());
pipeline.addLast(new EgtsProtocolDecoder(EgtsProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/EgtsProtocolDecoder.java b/src/main/java/org/traccar/protocol/EgtsProtocolDecoder.java
index e65ddb0ef..01d329580 100644
--- a/src/main/java/org/traccar/protocol/EgtsProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/EgtsProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -291,7 +291,7 @@ public class EgtsProtocolDecoder extends BaseProtocolDecoder {
if (serviceType == SERVICE_TELEDATA && position.getValid()) {
if (useObjectIdAsDeviceId && objectId != 0L) {
- deviceSession = getDeviceSession(channel, remoteAddress, true, String.valueOf(objectId));
+ deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(objectId));
if (deviceSession != null) {
position.setDeviceId(deviceSession.getDeviceId());
}
diff --git a/src/main/java/org/traccar/protocol/EnforaProtocol.java b/src/main/java/org/traccar/protocol/EnforaProtocol.java
index e462ab322..3b796db25 100644
--- a/src/main/java/org/traccar/protocol/EnforaProtocol.java
+++ b/src/main/java/org/traccar/protocol/EnforaProtocol.java
@@ -19,26 +19,30 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class EnforaProtocol extends BaseProtocol {
- public EnforaProtocol() {
+ @Inject
+ public EnforaProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 2, -2, 2));
pipeline.addLast(new EnforaProtocolEncoder(EnforaProtocol.this));
pipeline.addLast(new EnforaProtocolDecoder(EnforaProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new EnforaProtocolEncoder(EnforaProtocol.this));
pipeline.addLast(new EnforaProtocolDecoder(EnforaProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/EnforaProtocolDecoder.java b/src/main/java/org/traccar/protocol/EnforaProtocolDecoder.java
index bfa7a116b..dd1c8017b 100644
--- a/src/main/java/org/traccar/protocol/EnforaProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/EnforaProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BufferUtil;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/EnnfuProtocol.java b/src/main/java/org/traccar/protocol/EnnfuProtocol.java
index 7ef94d83f..a3ff943fa 100644
--- a/src/main/java/org/traccar/protocol/EnnfuProtocol.java
+++ b/src/main/java/org/traccar/protocol/EnnfuProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class EnnfuProtocol extends BaseProtocol {
- public EnnfuProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public EnnfuProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '$'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/EnnfuProtocolDecoder.java b/src/main/java/org/traccar/protocol/EnnfuProtocolDecoder.java
index 792ed1098..2198938e2 100644
--- a/src/main/java/org/traccar/protocol/EnnfuProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/EnnfuProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/EnvotechProtocol.java b/src/main/java/org/traccar/protocol/EnvotechProtocol.java
index 8eb71ee6b..e432ac07c 100644
--- a/src/main/java/org/traccar/protocol/EnvotechProtocol.java
+++ b/src/main/java/org/traccar/protocol/EnvotechProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class EnvotechProtocol extends BaseProtocol {
- public EnvotechProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public EnvotechProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/EnvotechProtocolDecoder.java b/src/main/java/org/traccar/protocol/EnvotechProtocolDecoder.java
index 083d8a921..750ff2bda 100644
--- a/src/main/java/org/traccar/protocol/EnvotechProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/EnvotechProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
@@ -48,14 +48,15 @@ public class EnvotechProtocolDecoder extends BaseProtocolDecoder {
.number("(ddd),") // battery
.number("(xx)") // inputs
.number("(xx),") // outputs
- .number("(xxx)?,") // fuel
+ .number("(xxx)?") // fuel
+ .number("(xxx)?,") // weight
.number("(x{8}),") // status
.expression("[^']*'")
.number("(dd)(dd)(dd)") // date (ddmmyy)
.number("(dd)(dd)(dd)") // time (hhmmss)
.number("(d)") // fix
- .number("(dd)(dd)(d+)([NS])") // latitude
- .number("(ddd)(dd)(d+)([EW])") // longitude
+ .number("(d+)(d{5})([NS])") // latitude
+ .number("(d+)(d{5})([EW])") // longitude
.number("(ddd)") // speed
.number("(ddd)") // course
.any()
@@ -72,7 +73,18 @@ public class EnvotechProtocolDecoder extends BaseProtocolDecoder {
Position position = new Position(getProtocolName());
- position.set(Position.KEY_EVENT, parser.nextHexInt());
+ int event = parser.nextHexInt();
+ switch (event) {
+ case 0x60:
+ position.set(Position.KEY_ALARM, Position.ALARM_LOCK);
+ break;
+ case 0x61:
+ position.set(Position.KEY_ALARM, Position.ALARM_UNLOCK);
+ break;
+ default:
+ break;
+ }
+ position.set(Position.KEY_EVENT, event);
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
if (deviceSession == null) {
@@ -88,12 +100,13 @@ public class EnvotechProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_INPUT, parser.nextHexInt());
position.set(Position.PREFIX_OUT, parser.nextHexInt());
position.set(Position.KEY_FUEL_LEVEL, parser.nextHexInt());
- position.set(Position.KEY_STATUS, parser.nextHexInt());
+ position.set("weight", parser.nextHexInt());
+ position.set(Position.KEY_STATUS, parser.nextHexLong());
position.setFixTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
position.setValid(parser.nextInt() > 0);
- position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN_HEM));
- position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN_HEM));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_DEG_HEM));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_DEG_HEM));
position.setSpeed(parser.nextInt());
position.setCourse(parser.nextInt());
diff --git a/src/main/java/org/traccar/protocol/EsealProtocol.java b/src/main/java/org/traccar/protocol/EsealProtocol.java
index fc1d342e1..eae4cf2aa 100644
--- a/src/main/java/org/traccar/protocol/EsealProtocol.java
+++ b/src/main/java/org/traccar/protocol/EsealProtocol.java
@@ -21,18 +21,22 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class EsealProtocol extends BaseProtocol {
- public EsealProtocol() {
+ @Inject
+ public EsealProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_ALARM_ARM,
Command.TYPE_ALARM_DISARM);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/EsealProtocolDecoder.java b/src/main/java/org/traccar/protocol/EsealProtocolDecoder.java
index 0a12f781d..dd15c4276 100644
--- a/src/main/java/org/traccar/protocol/EsealProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/EsealProtocolDecoder.java
@@ -17,8 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.config.Keys;
@@ -32,11 +31,15 @@ import java.util.regex.Pattern;
public class EsealProtocolDecoder extends BaseProtocolDecoder {
- private final String config;
+ private String config;
public EsealProtocolDecoder(Protocol protocol) {
super(protocol);
- config = Context.getConfig().getString(Keys.PROTOCOL_CONFIG.withPrefix(getProtocolName()));
+ }
+
+ @Override
+ protected void init() {
+ config = getConfig().getString(Keys.PROTOCOL_CONFIG.withPrefix(getProtocolName()));
}
private static final Pattern PATTERN = new PatternBuilder()
diff --git a/src/main/java/org/traccar/protocol/EskyProtocol.java b/src/main/java/org/traccar/protocol/EskyProtocol.java
index fb047c207..002e268ba 100644
--- a/src/main/java/org/traccar/protocol/EskyProtocol.java
+++ b/src/main/java/org/traccar/protocol/EskyProtocol.java
@@ -20,22 +20,26 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class EskyProtocol extends BaseProtocol {
- public EskyProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public EskyProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new EskyFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new EskyProtocolDecoder(EskyProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new EskyProtocolDecoder(EskyProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java b/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java
index 14b4376d5..4239022d0 100644
--- a/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/EskyProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import io.netty.channel.socket.DatagramChannel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/ExtremTracProtocol.java b/src/main/java/org/traccar/protocol/ExtremTracProtocol.java
index 692fd4e99..23a993fe4 100644
--- a/src/main/java/org/traccar/protocol/ExtremTracProtocol.java
+++ b/src/main/java/org/traccar/protocol/ExtremTracProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class ExtremTracProtocol extends BaseProtocol {
- public ExtremTracProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public ExtremTracProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/ExtremTracProtocolDecoder.java b/src/main/java/org/traccar/protocol/ExtremTracProtocolDecoder.java
index 9fde6f0a0..706c70825 100644
--- a/src/main/java/org/traccar/protocol/ExtremTracProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ExtremTracProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocol.java b/src/main/java/org/traccar/protocol/FifotrackProtocol.java
index 4a0a12ed3..e98ad84cc 100644
--- a/src/main/java/org/traccar/protocol/FifotrackProtocol.java
+++ b/src/main/java/org/traccar/protocol/FifotrackProtocol.java
@@ -19,17 +19,21 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class FifotrackProtocol extends BaseProtocol {
- public FifotrackProtocol() {
+ @Inject
+ public FifotrackProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_REQUEST_PHOTO);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new FifotrackFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new FifotrackProtocolEncoder(FifotrackProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java
index 5f9326a61..87587aa1e 100644
--- a/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/FifotrackProtocolDecoder.java
@@ -19,8 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -35,6 +34,10 @@ import org.traccar.model.WifiAccessPoint;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
import java.util.regex.Pattern;
public class FifotrackProtocolDecoder extends BaseProtocolDecoder {
@@ -61,7 +64,7 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder {
.number("(d+),") // course
.number("(-?d+),") // altitude
.number("(d+),") // odometer
- .number("d+,") // runtime
+ .number("(d+),") // engine hours
.number("(x+),") // status
.number("(x+)?,") // input
.number("(x+)?,") // output
@@ -79,7 +82,7 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder {
.text("$$")
.number("d+,") // length
.number("(d+),") // imei
- .number("x+,") // index
+ .number("(x+),") // index
.text("A03,") // type
.number("(d+)?,") // alarm
.number("(dd)(dd)(dd)") // date (yymmdd)
@@ -138,16 +141,20 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder {
.number("xx")
.compile();
- private void requestPhoto(Channel channel, SocketAddress socketAddress, String imei, String file) {
+ private void sendResponse(Channel channel, SocketAddress remoteAddress, String imei, String content) {
if (channel != null) {
- String content = "1,D06," + file + "," + photo.writerIndex() + "," + Math.min(1024, photo.writableBytes());
int length = 1 + imei.length() + 1 + content.length();
String response = String.format("##%02d,%s,%s*", length, imei, content);
response += Checksum.sum(response) + "\r\n";
- channel.writeAndFlush(new NetworkMessage(response, socketAddress));
+ channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
}
}
+ private void requestPhoto(Channel channel, SocketAddress remoteAddress, String imei, String file) {
+ String content = "1,D06," + file + "," + photo.writerIndex() + "," + Math.min(1024, photo.writableBytes());
+ sendResponse(channel, remoteAddress, imei, content);
+ }
+
private String decodeAlarm(Integer alarm) {
if (alarm != null) {
switch (alarm) {
@@ -201,11 +208,14 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ String imei = parser.next();
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
if (deviceSession == null) {
return null;
}
+ String index = parser.next();
+
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
@@ -225,13 +235,15 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder {
position.setValid(parser.next().equals("A"));
position.setFixTime(position.getDeviceTime());
- position.set(Position.KEY_SATELLITES, parser.nextInt());
position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt()));
+ position.set(Position.KEY_SATELLITES, parser.nextInt());
position.setLatitude(parser.nextDouble());
position.setLongitude(parser.nextDouble());
} else {
+ getLastLocation(position, position.getDeviceTime());
+
String[] points = parser.next().split("\\|");
for (String point : points) {
String[] wifi = point.split(":");
@@ -244,6 +256,11 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder {
position.setNetwork(network);
+ DateFormat dateFormat = new SimpleDateFormat("yyMMddHHmmss");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ String response = index + ",A03," + dateFormat.format(new Date());
+ sendResponse(channel, remoteAddress, imei, response);
+
return position;
}
@@ -275,6 +292,7 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder {
position.setAltitude(parser.nextInt());
position.set(Position.KEY_ODOMETER, parser.nextLong());
+ position.set(Position.KEY_HOURS, parser.nextLong() * 1000);
long status = parser.nextHexLong();
position.set(Position.KEY_RSSI, BitUtil.between(status, 3, 8));
@@ -293,11 +311,11 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder {
}
if (parser.hasNext()) {
- String rfid = parser.next();
- if (rfid.matches("\\p{XDigit}+")) {
- position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(Integer.parseInt(rfid, 16)));
+ String value = parser.next();
+ if (value.matches("\\p{XDigit}+")) {
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(Integer.parseInt(value, 16)));
} else {
- position.set("driverLicense", rfid);
+ position.set(Position.KEY_CARD, value);
}
}
@@ -381,7 +399,7 @@ public class FifotrackProtocolDecoder extends BaseProtocolDecoder {
Position position = new Position(getProtocolName());
position.setDeviceId(getDeviceSession(channel, remoteAddress, imei).getDeviceId());
getLastLocation(position, null);
- position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(imei, photo, "jpg"));
+ position.set(Position.KEY_IMAGE, writeMediaFile(imei, photo, "jpg"));
photo.release();
photo = null;
return position;
diff --git a/src/main/java/org/traccar/protocol/FlespiProtocol.java b/src/main/java/org/traccar/protocol/FlespiProtocol.java
index 05b105f93..0d8448845 100644
--- a/src/main/java/org/traccar/protocol/FlespiProtocol.java
+++ b/src/main/java/org/traccar/protocol/FlespiProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class FlespiProtocol extends BaseProtocol {
- public FlespiProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public FlespiProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder(4096, 8192, 128 * 1024));
pipeline.addLast(new HttpObjectAggregator(Integer.MAX_VALUE));
diff --git a/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java
index 83ca74ce5..ea076afd8 100644
--- a/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2020 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.
@@ -19,17 +19,17 @@ import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
-import javax.json.Json;
-import javax.json.JsonArray;
-import javax.json.JsonNumber;
-import javax.json.JsonObject;
-import javax.json.JsonString;
-import javax.json.JsonValue;
+import jakarta.json.Json;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonNumber;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonString;
+import jakarta.json.JsonValue;
import java.io.StringReader;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
@@ -54,11 +54,11 @@ public class FlespiProtocolDecoder extends BaseHttpProtocolDecoder {
List<Position> positions = new LinkedList<>();
for (int i = 0; i < result.size(); i++) {
JsonObject message = result.getJsonObject(i);
- JsonString ident = message.getJsonString("ident");
- if (ident == null) {
+ JsonString identifier = message.getJsonString("ident");
+ if (identifier == null) {
continue;
}
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, ident.getString());
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, identifier.getString());
if (deviceSession == null) {
continue;
}
@@ -125,12 +125,13 @@ public class FlespiProtocolDecoder extends BaseHttpProtocolDecoder {
position.set(Position.KEY_PDOP, ((JsonNumber) value).doubleValue());
return true;
case "din":
+ position.set(Position.KEY_INPUT, ((JsonNumber) value).intValue());
+ return true;
case "dout":
- if (name.equals("din")) {
- position.set(Position.KEY_INPUT, ((JsonNumber) value).intValue());
- } else {
- position.set(Position.KEY_OUTPUT, ((JsonNumber) value).intValue());
- }
+ position.set(Position.KEY_OUTPUT, ((JsonNumber) value).intValue());
+ return true;
+ case "report.reason":
+ position.set(Position.KEY_EVENT, ((JsonNumber) value).intValue());
return true;
case "gps.vehicle.mileage":
position.set(Position.KEY_ODOMETER, ((JsonNumber) value).doubleValue());
@@ -141,6 +142,9 @@ public class FlespiProtocolDecoder extends BaseHttpProtocolDecoder {
case "battery.voltage":
position.set(Position.KEY_BATTERY, ((JsonNumber) value).doubleValue());
return true;
+ case "battery.level":
+ position.set(Position.KEY_BATTERY_LEVEL, ((JsonNumber) value).intValue());
+ return true;
case "fuel.level":
case "can.fuel.level":
position.set(Position.KEY_FUEL_LEVEL, ((JsonNumber) value).doubleValue());
@@ -228,6 +232,15 @@ public class FlespiProtocolDecoder extends BaseHttpProtocolDecoder {
position.set(Position.KEY_ALARM, Position.ALARM_BONNET);
}
return true;
+ case "custom.wln_accel_max":
+ position.set("maxAcceleration", ((JsonNumber) value).doubleValue());
+ return true;
+ case "custom.wln_brk_max":
+ position.set("maxBraking", ((JsonNumber) value).doubleValue());
+ return true;
+ case "custom.wln_crn_max":
+ position.set("maxCornering", ((JsonNumber) value).doubleValue());
+ return true;
default:
return false;
}
diff --git a/src/main/java/org/traccar/protocol/FlexApiProtocol.java b/src/main/java/org/traccar/protocol/FlexApiProtocol.java
index 7f4154f71..b2e3f5d00 100644
--- a/src/main/java/org/traccar/protocol/FlexApiProtocol.java
+++ b/src/main/java/org/traccar/protocol/FlexApiProtocol.java
@@ -20,15 +20,19 @@ import io.netty.handler.codec.string.StringDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import java.nio.charset.StandardCharsets;
+import jakarta.inject.Inject;
+
public class FlexApiProtocol extends BaseProtocol {
- public FlexApiProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public FlexApiProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(5120));
pipeline.addLast(new StringDecoder(StandardCharsets.US_ASCII));
pipeline.addLast(new FlexApiProtocolDecoder(FlexApiProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java
index bcfbdd7da..fb76673ca 100644
--- a/src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java
@@ -17,14 +17,14 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.model.CellTower;
import org.traccar.model.Network;
import org.traccar.model.Position;
-import javax.json.Json;
-import javax.json.JsonObject;
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
import java.io.StringReader;
import java.net.SocketAddress;
import java.util.Date;
diff --git a/src/main/java/org/traccar/protocol/FlexCommProtocol.java b/src/main/java/org/traccar/protocol/FlexCommProtocol.java
index 9343ebeb8..293b9b12b 100644
--- a/src/main/java/org/traccar/protocol/FlexCommProtocol.java
+++ b/src/main/java/org/traccar/protocol/FlexCommProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class FlexCommProtocol extends BaseProtocol {
- public FlexCommProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public FlexCommProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new FixedLengthFrameDecoder(2 + 2 + 101 + 5));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/FlexCommProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlexCommProtocolDecoder.java
index 068c0a05c..0d8bd9373 100644
--- a/src/main/java/org/traccar/protocol/FlexCommProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/FlexCommProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/FlexibleReportProtocol.java b/src/main/java/org/traccar/protocol/FlexibleReportProtocol.java
index 0cd55343a..a16e61458 100644
--- a/src/main/java/org/traccar/protocol/FlexibleReportProtocol.java
+++ b/src/main/java/org/traccar/protocol/FlexibleReportProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class FlexibleReportProtocol extends BaseProtocol {
- public FlexibleReportProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public FlexibleReportProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new FlexibleReportProtocolDecoder(FlexibleReportProtocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/FlexibleReportProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlexibleReportProtocolDecoder.java
index 759f2cd6f..9fcee1aeb 100644
--- a/src/main/java/org/traccar/protocol/FlexibleReportProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/FlexibleReportProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/FlextrackProtocol.java b/src/main/java/org/traccar/protocol/FlextrackProtocol.java
index ddd1d58f0..b6353de9d 100644
--- a/src/main/java/org/traccar/protocol/FlextrackProtocol.java
+++ b/src/main/java/org/traccar/protocol/FlextrackProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class FlextrackProtocol extends BaseProtocol {
- public FlextrackProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public FlextrackProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\r"));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/FlextrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/FlextrackProtocolDecoder.java
index 9dce22ede..a0dac1c41 100644
--- a/src/main/java/org/traccar/protocol/FlextrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/FlextrackProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/FoxProtocol.java b/src/main/java/org/traccar/protocol/FoxProtocol.java
index 9bac773b5..edb496f11 100644
--- a/src/main/java/org/traccar/protocol/FoxProtocol.java
+++ b/src/main/java/org/traccar/protocol/FoxProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class FoxProtocol extends BaseProtocol {
- public FoxProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public FoxProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "</fox>"));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/FoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/FoxProtocolDecoder.java
index 449f00022..6dd0b0e95 100644
--- a/src/main/java/org/traccar/protocol/FoxProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/FoxProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/FreedomProtocol.java b/src/main/java/org/traccar/protocol/FreedomProtocol.java
index bc6b92d5f..87404094a 100644
--- a/src/main/java/org/traccar/protocol/FreedomProtocol.java
+++ b/src/main/java/org/traccar/protocol/FreedomProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class FreedomProtocol extends BaseProtocol {
- public FreedomProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public FreedomProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/FreedomProtocolDecoder.java b/src/main/java/org/traccar/protocol/FreedomProtocolDecoder.java
index 1d2dd3133..27dda1a6d 100644
--- a/src/main/java/org/traccar/protocol/FreedomProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/FreedomProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/FreematicsProtocol.java b/src/main/java/org/traccar/protocol/FreematicsProtocol.java
index 999b075a1..c4076f330 100644
--- a/src/main/java/org/traccar/protocol/FreematicsProtocol.java
+++ b/src/main/java/org/traccar/protocol/FreematicsProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class FreematicsProtocol extends BaseProtocol {
- public FreematicsProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public FreematicsProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new FreematicsProtocolDecoder(FreematicsProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java b/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java
index aded35823..4d8e7e7ea 100644
--- a/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/FreematicsProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Checksum;
@@ -153,7 +153,7 @@ public class FreematicsProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_RSSI, Integer.parseInt(value));
break;
case 0x82:
- position.set(Position.KEY_DEVICE_TEMP, Integer.parseInt(value) * 0.1);
+ position.set(Position.KEY_DEVICE_TEMP, Double.parseDouble(value) * 0.1);
break;
case 0x104:
position.set(Position.KEY_ENGINE_LOAD, Integer.parseInt(value));
diff --git a/src/main/java/org/traccar/protocol/FutureWayProtocol.java b/src/main/java/org/traccar/protocol/FutureWayProtocol.java
index 73b53ee12..20586bede 100644
--- a/src/main/java/org/traccar/protocol/FutureWayProtocol.java
+++ b/src/main/java/org/traccar/protocol/FutureWayProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class FutureWayProtocol extends BaseProtocol {
- public FutureWayProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public FutureWayProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new FutureWayFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/FutureWayProtocolDecoder.java b/src/main/java/org/traccar/protocol/FutureWayProtocolDecoder.java
index c2f3781d9..57027b080 100644
--- a/src/main/java/org/traccar/protocol/FutureWayProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/FutureWayProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DataConverter;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/G1rusFrameDecoder.java b/src/main/java/org/traccar/protocol/G1rusFrameDecoder.java
new file mode 100644
index 000000000..8c67207ad
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/G1rusFrameDecoder.java
@@ -0,0 +1,49 @@
+/*
+ * 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.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import org.traccar.BaseFrameDecoder;
+
+public class G1rusFrameDecoder extends BaseFrameDecoder {
+
+ @Override
+ protected Object decode(
+ ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception {
+
+ ByteBuf result = Unpooled.buffer();
+
+ while (buf.isReadable()) {
+ int b = buf.readUnsignedByte();
+ if (b == 0x1B) {
+ int ext = buf.readUnsignedByte();
+ if (ext == 0x00) {
+ result.writeByte(0x1B);
+ } else {
+ result.writeByte(0xF8);
+ }
+ } else {
+ result.writeByte(b);
+ }
+ }
+
+ return result;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/G1rusProtocol.java b/src/main/java/org/traccar/protocol/G1rusProtocol.java
new file mode 100644
index 000000000..b3904b357
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/G1rusProtocol.java
@@ -0,0 +1,40 @@
+/*
+ * 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.protocol;
+
+import io.netty.handler.codec.string.StringEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
+
+public class G1rusProtocol extends BaseProtocol {
+
+ @Inject
+ public G1rusProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new G1rusFrameDecoder());
+ pipeline.addLast(new StringEncoder());
+ pipeline.addLast(new G1rusProtocolDecoder(G1rusProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/G1rusProtocolDecoder.java b/src/main/java/org/traccar/protocol/G1rusProtocolDecoder.java
new file mode 100644
index 000000000..17cfbc1eb
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/G1rusProtocolDecoder.java
@@ -0,0 +1,165 @@
+/*
+ * 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.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.Protocol;
+import org.traccar.helper.BitUtil;
+import org.traccar.model.Position;
+import org.traccar.session.DeviceSession;
+
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+public class G1rusProtocolDecoder extends BaseProtocolDecoder {
+ public G1rusProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ public static final int MSG_HEARTBEAT = 0;
+ public static final int MSG_REGULAR = 1;
+ public static final int MSG_SMS_FORWARD = 2;
+ public static final int MSG_SERIAL = 3;
+ public static final int MSG_MIXED = 4;
+
+ private String readString(ByteBuf buf) {
+ int length = buf.readUnsignedByte() & 0xF;
+ return buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
+ }
+
+ private Position decodeRegular(DeviceSession deviceSession, ByteBuf buf, int type) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+ position.setTime(new Date((buf.readUnsignedIntLE() + 946684800) * 1000L));
+
+ if (BitUtil.check(type, 6)) {
+ position.set(Position.KEY_EVENT, buf.readUnsignedByte());
+ }
+
+ int dataMask = buf.readUnsignedShort();
+
+ if (BitUtil.check(dataMask, 0)) {
+ buf.readUnsignedByte(); // length
+ readString(buf); // device name
+ position.set(Position.KEY_VERSION_FW, readString(buf));
+ position.set(Position.KEY_VERSION_HW, readString(buf));
+ }
+
+ if (BitUtil.check(dataMask, 1)) {
+ buf.readUnsignedByte(); // length
+ int locationMask = buf.readUnsignedShort();
+ if (BitUtil.check(locationMask, 0)) {
+ int validity = buf.readUnsignedByte();
+ position.set(Position.KEY_SATELLITES, BitUtil.to(validity, 5));
+ position.setValid(BitUtil.between(validity, 5, 7) == 2);
+ }
+ if (BitUtil.check(locationMask, 1)) {
+ position.setLatitude(buf.readInt() / 1000000.0);
+ position.setLongitude(buf.readInt() / 1000000.0);
+ }
+ if (BitUtil.check(locationMask, 2)) {
+ position.setSpeed(buf.readUnsignedShort());
+ }
+ if (BitUtil.check(locationMask, 3)) {
+ position.setCourse(buf.readUnsignedShort());
+ }
+ if (BitUtil.check(locationMask, 4)) {
+ position.setAltitude(buf.readShort());
+ }
+ if (BitUtil.check(locationMask, 5)) {
+ position.set(Position.KEY_HDOP, buf.readUnsignedShort());
+ }
+ if (BitUtil.check(locationMask, 6)) {
+ position.set(Position.KEY_VDOP, buf.readUnsignedShort());
+ }
+ }
+
+ if (BitUtil.check(dataMask, 2)) {
+ buf.skipBytes(buf.readUnsignedByte());
+ }
+
+ if (BitUtil.check(dataMask, 3)) {
+ buf.skipBytes(buf.readUnsignedByte());
+ }
+
+ if (BitUtil.check(dataMask, 4)) {
+ buf.readUnsignedByte(); // length
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 110 / 4096 - 10);
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 110 / 4096 - 10);
+ position.set(Position.KEY_DEVICE_TEMP, buf.readUnsignedShort() * 110 / 4096 - 10);
+ }
+
+ if (BitUtil.check(dataMask, 5)) {
+ buf.skipBytes(buf.readUnsignedByte());
+ }
+
+ if (BitUtil.check(dataMask, 7)) {
+ buf.skipBytes(buf.readUnsignedByte());
+ }
+
+ return position;
+ }
+
+ @Override
+ protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ByteBuf buf = (ByteBuf) msg;
+
+ buf.readUnsignedByte(); // header
+ buf.readUnsignedByte(); // version
+
+ int type = buf.readUnsignedByte();
+ String imei = String.valueOf(buf.readLong());
+ buf.readerIndex(buf.readerIndex() - 1);
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ if (BitUtil.to(type, 6) == MSG_REGULAR) {
+
+ return decodeRegular(deviceSession, buf, type);
+
+ } else if (BitUtil.to(type, 6) == MSG_MIXED) {
+
+ List<Position> positions = new LinkedList<>();
+ while (buf.readableBytes() > 5) {
+ int length = buf.readUnsignedShort();
+ int subtype = buf.readUnsignedByte();
+ if (BitUtil.to(subtype, 6) == MSG_REGULAR) {
+ positions.add(decodeRegular(deviceSession, buf, subtype));
+ } else {
+ buf.skipBytes(length - 1);
+ }
+ }
+ return positions.isEmpty() ? null : positions;
+
+ }
+
+ buf.readUnsignedShort(); // checksum
+ buf.readUnsignedByte(); // tail
+
+ return null;
+
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java b/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java
index c23d26c83..d90e48287 100644
--- a/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java
+++ b/src/main/java/org/traccar/protocol/GalileoFrameDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ import org.traccar.BaseFrameDecoder;
public class GalileoFrameDecoder extends BaseFrameDecoder {
- private static final int MESSAGE_MINIMUM_LENGTH = 5;
+ private static final int MESSAGE_MINIMUM_LENGTH = 6;
@Override
protected Object decode(
@@ -32,9 +32,15 @@ public class GalileoFrameDecoder extends BaseFrameDecoder {
return null;
}
- int length = buf.getUnsignedShortLE(buf.readerIndex() + 1) & 0x7fff;
- if (buf.readableBytes() >= (length + MESSAGE_MINIMUM_LENGTH)) {
- return buf.readRetainedSlice(length + MESSAGE_MINIMUM_LENGTH);
+ int length;
+ if (buf.getByte(buf.readerIndex()) == 0x01 && buf.getUnsignedMedium(buf.readerIndex() + 3) == 0x01001c) {
+ length = 3 + buf.getUnsignedShort(buf.readerIndex() + 1);
+ } else {
+ length = 5 + (buf.getUnsignedShortLE(buf.readerIndex() + 1) & 0x7fff);
+ }
+
+ if (buf.readableBytes() >= length) {
+ return buf.readRetainedSlice(length);
}
return null;
diff --git a/src/main/java/org/traccar/protocol/GalileoProtocol.java b/src/main/java/org/traccar/protocol/GalileoProtocol.java
index a1570c9b0..95ce4edde 100644
--- a/src/main/java/org/traccar/protocol/GalileoProtocol.java
+++ b/src/main/java/org/traccar/protocol/GalileoProtocol.java
@@ -18,17 +18,21 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class GalileoProtocol extends BaseProtocol {
- public GalileoProtocol() {
+ @Inject
+ public GalileoProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_OUTPUT_CONTROL);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new GalileoFrameDecoder());
pipeline.addLast(new GalileoProtocolEncoder(GalileoProtocol.this));
pipeline.addLast(new GalileoProtocolDecoder(GalileoProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/GalileoProtocolDecoder.java b/src/main/java/org/traccar/protocol/GalileoProtocolDecoder.java
index f29fb9850..44baa94ea 100644
--- a/src/main/java/org/traccar/protocol/GalileoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GalileoProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,15 +20,19 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
+import org.traccar.config.Keys;
+import org.traccar.helper.BitBuffer;
+import org.traccar.helper.BitUtil;
import org.traccar.helper.UnitsConverter;
+import org.traccar.helper.model.AttributeUtil;
import org.traccar.model.Position;
+import org.traccar.session.DeviceSession;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
+import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -36,6 +40,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.TimeZone;
public class GalileoProtocolDecoder extends BaseProtocolDecoder {
@@ -44,6 +49,17 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
}
private ByteBuf photo;
+ private boolean compressed;
+
+ public void setCompressed(boolean compressed) {
+ this.compressed = compressed;
+ }
+
+ public boolean getCompressed(long deviceId) {
+ Boolean value = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_EXTENDED.withPrefix(getProtocolName()), deviceId);
+ return value != null ? value : compressed;
+ }
private static final Map<Integer, Integer> TAG_LENGTH_MAP = new HashMap<>();
@@ -64,7 +80,7 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
};
int[] l3 = {
0x63, 0x64, 0x6f, 0x5d, 0x65, 0x66, 0x67, 0x68,
- 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e
+ 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0xfa
};
int[] l4 = {
0x20, 0x33, 0x44, 0x90, 0xc0, 0xc2, 0xc3, 0xd3,
@@ -86,6 +102,8 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
}
TAG_LENGTH_MAP.put(0x5b, 7); // variable length
TAG_LENGTH_MAP.put(0x5c, 68);
+ TAG_LENGTH_MAP.put(0xfd, 8);
+ TAG_LENGTH_MAP.put(0xfe, 8);
}
private static int getTagLength(int tag) {
@@ -215,7 +233,6 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
break;
case 0xea:
position.set("userDataArray", ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte())));
- position.set("userDataArray", ByteBufUtil.hexDump(buf.readSlice(buf.readUnsignedByte())));
break;
default:
buf.skipBytes(getTagLength(tag));
@@ -231,18 +248,105 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
int header = buf.readUnsignedByte();
if (header == 0x01) {
- return decodePositions(channel, remoteAddress, buf);
+ if (buf.getUnsignedMedium(buf.readerIndex() + 2) == 0x01001c) {
+ return decodeIridiumPosition(channel, remoteAddress, buf);
+ } else {
+ return decodePositions(channel, remoteAddress, buf);
+ }
} else if (header == 0x07) {
return decodePhoto(channel, remoteAddress, buf);
+ } else if (header == 0x08) {
+ return decodeCompressedPositions(channel, remoteAddress, buf);
}
return null;
}
- private Object decodePositions(
- Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception {
+ private void decodeMinimalDataSet(Position position, ByteBuf buf) {
+ BitBuffer bits = new BitBuffer(buf.readSlice(10));
+ bits.readUnsigned(1);
+
+ Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ calendar.set(Calendar.DAY_OF_YEAR, 1);
+ calendar.set(Calendar.HOUR_OF_DAY, calendar.getActualMinimum(Calendar.HOUR_OF_DAY));
+ calendar.set(Calendar.MINUTE, calendar.getActualMinimum(Calendar.MINUTE));
+ calendar.set(Calendar.SECOND, calendar.getActualMinimum(Calendar.SECOND));
+ calendar.set(Calendar.MILLISECOND, calendar.getActualMinimum(Calendar.MILLISECOND));
+ calendar.add(Calendar.SECOND, bits.readUnsigned(25));
+ position.setTime(calendar.getTime());
+
+ position.setValid(bits.readUnsigned(1) == 0);
+ position.setLongitude(360 * bits.readUnsigned(22) / 4194304.0 - 180);
+ position.setLatitude(180 * bits.readUnsigned(21) / 2097152.0 - 90);
+ if (bits.readUnsigned(1) > 0) {
+ position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
+ }
+ }
+
+ private Position decodeIridiumPosition(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
+
+ buf.readUnsignedShort(); // length
+
+ buf.skipBytes(3); // identification header
+ buf.readUnsignedInt(); // index
- int length = (buf.readUnsignedShortLE() & 0x7fff) + 3;
+ DeviceSession deviceSession = getDeviceSession(
+ channel, remoteAddress, buf.readSlice(15).toString(StandardCharsets.US_ASCII));
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ buf.readUnsignedByte(); // session status
+ buf.skipBytes(4); // reserved
+ position.setTime(new Date(buf.readUnsignedInt() * 1000));
+
+ buf.skipBytes(3); // coordinates header
+ int flags = buf.readUnsignedByte();
+ double latitude = buf.readUnsignedByte() + buf.readUnsignedShort() / 60000.0;
+ double longitude = buf.readUnsignedByte() + buf.readUnsignedShort() / 60000.0;
+ position.setLatitude(BitUtil.check(flags, 1) ? -latitude : latitude);
+ position.setLongitude(BitUtil.check(flags, 0) ? -longitude : longitude);
+ buf.readUnsignedInt(); // accuracy
+
+ buf.readUnsignedByte(); // data tag header
+ ByteBuf data = buf.readSlice(buf.readUnsignedShort());
+ if (getCompressed(deviceSession.getDeviceId())) {
+
+ decodeMinimalDataSet(position, data);
+
+ int[] tags = new int[BitUtil.to(data.readUnsignedByte(), 8)];
+ for (int i = 0; i < tags.length; i++) {
+ tags[i] = data.readUnsignedByte();
+ }
+
+ for (int tag : tags) {
+ decodeTag(position, data, tag);
+ }
+
+ } else {
+
+ while (data.isReadable()) {
+ int tag = data.readUnsignedByte();
+ if (tag == 0x30) {
+ position.setValid((data.readUnsignedByte() & 0xf0) == 0x00);
+ position.setLatitude(data.readIntLE() / 1000000.0);
+ position.setLongitude(data.readIntLE() / 1000000.0);
+ } else {
+ decodeTag(position, data, tag);
+ }
+ }
+
+ }
+
+ return position;
+ }
+
+ private List<Position> decodePositions(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
+
+ int endIndex = (buf.readUnsignedShortLE() & 0x7fff) + buf.readerIndex();
List<Position> positions = new LinkedList<>();
Set<Integer> tags = new HashSet<>();
@@ -251,7 +355,7 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
DeviceSession deviceSession = null;
Position position = new Position(getProtocolName());
- while (buf.readerIndex() < length) {
+ while (buf.readerIndex() < endIndex) {
int tag = buf.readUnsignedByte();
if (tags.contains(tag)) {
@@ -287,7 +391,7 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
if (hasLocation && position.getFixTime() != null) {
positions.add(position);
- } else if (position.getAttributes().containsKey(Position.KEY_RESULT)) {
+ } else if (position.hasAttribute(Position.KEY_RESULT)) {
position.setDeviceId(deviceSession.getDeviceId());
getLastLocation(position, null);
positions.add(position);
@@ -322,14 +426,13 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
} else {
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
- String uniqueId = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getUniqueId();
position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
getLastLocation(position, null);
- position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(uniqueId, photo, "jpg"));
+ position.set(Position.KEY_IMAGE, writeMediaFile(deviceSession.getUniqueId(), photo, "jpg"));
photo.release();
photo = null;
@@ -340,4 +443,43 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private List<Position> decodeCompressedPositions(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
+
+ buf.readUnsignedShortLE(); // length
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ List<Position> positions = new LinkedList<>();
+ while (buf.readableBytes() > 2) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ decodeMinimalDataSet(position, buf);
+
+ int[] tags = new int[BitUtil.to(buf.readUnsignedByte(), 8)];
+ for (int i = 0; i < tags.length; i++) {
+ tags[i] = buf.readUnsignedByte();
+ }
+
+ for (int tag : tags) {
+ decodeTag(position, buf, tag);
+ }
+
+ positions.add(position);
+
+ }
+
+ sendResponse(channel, 0x02, buf.readUnsignedShortLE());
+
+ for (Position p : positions) {
+ p.setDeviceId(deviceSession.getDeviceId());
+ }
+
+ return positions.isEmpty() ? null : positions;
+ }
+
}
diff --git a/src/main/java/org/traccar/protocol/GatorProtocol.java b/src/main/java/org/traccar/protocol/GatorProtocol.java
index ca81caefb..c961093ab 100644
--- a/src/main/java/org/traccar/protocol/GatorProtocol.java
+++ b/src/main/java/org/traccar/protocol/GatorProtocol.java
@@ -19,20 +19,27 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+import org.traccar.model.Command;
+
+import jakarta.inject.Inject;
public class GatorProtocol extends BaseProtocol {
- public GatorProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public GatorProtocol(Config config) {
+ setSupportedDataCommands(Command.TYPE_POSITION_SINGLE);
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2));
+ pipeline.addLast(new GatorProtocolEncoder(GatorProtocol.this));
pipeline.addLast(new GatorProtocolDecoder(GatorProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new GatorProtocolDecoder(GatorProtocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java
index 087861635..f7da5dc75 100644
--- a/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GatorProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BcdUtil;
@@ -37,6 +37,7 @@ public class GatorProtocolDecoder extends BaseProtocolDecoder {
}
public static final int MSG_HEARTBEAT = 0x21;
+ public static final int MSG_POSITION_REQUEST = 0x30;
public static final int MSG_POSITION_DATA = 0x80;
public static final int MSG_ROLLCALL_RESPONSE = 0x81;
public static final int MSG_ALARM_DATA = 0x82;
diff --git a/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java
new file mode 100644
index 000000000..3d38b7455
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/GatorProtocolEncoder.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2023 Hossain Mohammad Seym (seym45@gmail.com)
+ *
+ * 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.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import org.traccar.BaseProtocolEncoder;
+import org.traccar.Protocol;
+import org.traccar.helper.Checksum;
+import org.traccar.model.Command;
+
+public class GatorProtocolEncoder extends BaseProtocolEncoder {
+
+ public GatorProtocolEncoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ public ByteBuf encodeId(long deviceId) {
+ ByteBuf buf = Unpooled.buffer();
+
+ String id = getUniqueId(deviceId);
+
+ int firstDigit = Integer.parseInt(id.substring(1, 3)) - 30;
+
+ buf.writeByte(Integer.parseInt(id.substring(3, 5)) | (((firstDigit >> 3) & 1) << 7));
+ buf.writeByte(Integer.parseInt(id.substring(5, 7)) | (((firstDigit >> 2) & 1) << 7));
+ buf.writeByte(Integer.parseInt(id.substring(7, 9)) | (((firstDigit >> 1) & 1) << 7));
+ buf.writeByte(Integer.parseInt(id.substring(9)) | ((firstDigit & 1) << 7));
+
+ return buf;
+ }
+
+ private ByteBuf encodeContent(long deviceId, int type) {
+ ByteBuf buf = Unpooled.buffer();
+
+ buf.writeByte(0x24);
+ buf.writeByte(0x24);
+ buf.writeByte(type);
+ buf.writeByte(0x00);
+ buf.writeByte(4 + 1 + 1); // ip 4 bytes, checksum and end byte
+
+ ByteBuf pseudoIPAddress = encodeId(deviceId);
+ buf.writeBytes(pseudoIPAddress);
+
+ int checksum = Checksum.xor(buf.nioBuffer());
+ buf.writeByte(checksum);
+
+ buf.writeByte(0x0D);
+
+ return buf;
+ }
+
+ @Override
+ protected Object encodeCommand(Command command) {
+
+ switch (command.getType()) {
+ case Command.TYPE_POSITION_SINGLE:
+ return encodeContent(command.getDeviceId(), GatorProtocolDecoder.MSG_POSITION_REQUEST);
+ default:
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/org/traccar/protocol/GenxProtocol.java b/src/main/java/org/traccar/protocol/GenxProtocol.java
index c87ba946a..7e5a6a69e 100644
--- a/src/main/java/org/traccar/protocol/GenxProtocol.java
+++ b/src/main/java/org/traccar/protocol/GenxProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class GenxProtocol extends BaseProtocol {
- public GenxProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public GenxProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new GenxProtocolDecoder(GenxProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/GenxProtocolDecoder.java b/src/main/java/org/traccar/protocol/GenxProtocolDecoder.java
index 2ae9de7a0..6448b6a5a 100644
--- a/src/main/java/org/traccar/protocol/GenxProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GenxProtocolDecoder.java
@@ -17,8 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
@@ -32,7 +31,11 @@ public class GenxProtocolDecoder extends BaseProtocolDecoder {
public GenxProtocolDecoder(Protocol protocol) {
super(protocol);
- setReportColumns(Context.getConfig().getString(getProtocolName() + ".reportColumns", "1,2,3,4"));
+ }
+
+ @Override
+ protected void init() {
+ setReportColumns(getConfig().getString(getProtocolName() + ".reportColumns", "1,2,3,4"));
}
public void setReportColumns(String format) {
diff --git a/src/main/java/org/traccar/protocol/Gl100Protocol.java b/src/main/java/org/traccar/protocol/Gl100Protocol.java
index 063e606db..fdd79648f 100644
--- a/src/main/java/org/traccar/protocol/Gl100Protocol.java
+++ b/src/main/java/org/traccar/protocol/Gl100Protocol.java
@@ -21,22 +21,26 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Gl100Protocol extends BaseProtocol {
- public Gl100Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Gl100Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\0'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new Gl100ProtocolDecoder(Gl100Protocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new Gl100ProtocolDecoder(Gl100Protocol.this));
diff --git a/src/main/java/org/traccar/protocol/Gl100ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl100ProtocolDecoder.java
index ae0383e5c..789d87dad 100644
--- a/src/main/java/org/traccar/protocol/Gl100ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gl100ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/Gl200BinaryProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200BinaryProtocolDecoder.java
index c3339bea5..ecd1f5bfa 100644
--- a/src/main/java/org/traccar/protocol/Gl200BinaryProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gl200BinaryProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitBuffer;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/Gl200Protocol.java b/src/main/java/org/traccar/protocol/Gl200Protocol.java
index e2d0c6d2a..e3ddbb46e 100644
--- a/src/main/java/org/traccar/protocol/Gl200Protocol.java
+++ b/src/main/java/org/traccar/protocol/Gl200Protocol.java
@@ -15,34 +15,37 @@
*/
package org.traccar.protocol;
+import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
-import io.netty.handler.codec.string.StringEncoder;
+import jakarta.inject.Inject;
public class Gl200Protocol extends BaseProtocol {
- public Gl200Protocol() {
+ @Inject
+ public Gl200Protocol(Config config) {
setSupportedDataCommands(
Command.TYPE_POSITION_SINGLE,
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME,
Command.TYPE_IDENTIFICATION,
Command.TYPE_REBOOT_DEVICE);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new Gl200FrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new Gl200ProtocolEncoder(Gl200Protocol.this));
pipeline.addLast(new Gl200ProtocolDecoder(Gl200Protocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new Gl200ProtocolEncoder(Gl200Protocol.this));
pipeline.addLast(new Gl200ProtocolDecoder(Gl200Protocol.this));
diff --git a/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java
index ca1df7a13..9b4e05c35 100644
--- a/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gl200ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2018 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.
@@ -15,12 +15,14 @@
*/
package org.traccar.protocol;
+import com.google.inject.Injector;
import org.traccar.BaseProtocolDecoder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.Protocol;
+import jakarta.inject.Inject;
import java.net.SocketAddress;
public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
@@ -34,6 +36,12 @@ public class Gl200ProtocolDecoder extends BaseProtocolDecoder {
binaryProtocolDecoder = new Gl200BinaryProtocolDecoder(protocol);
}
+ @Inject
+ public void setInjector(Injector injector) {
+ injector.injectMembers(textProtocolDecoder);
+ injector.injectMembers(binaryProtocolDecoder);
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java
index 280986165..911af8d73 100644
--- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,9 +15,10 @@
*/
package org.traccar.protocol;
+import io.netty.buffer.Unpooled;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.helper.DataConverter;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.config.Keys;
@@ -46,11 +47,15 @@ import java.util.regex.Pattern;
public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
- private final boolean ignoreFixTime;
+ private boolean ignoreFixTime;
public Gl200TextProtocolDecoder(Protocol protocol) {
super(protocol);
- ignoreFixTime = Context.getConfig().getBoolean(Keys.PROTOCOL_IGNORE_FIX_TIME.withPrefix(getProtocolName()));
+ }
+
+ @Override
+ protected void init() {
+ ignoreFixTime = getConfig().getBoolean(Keys.PROTOCOL_IGNORE_FIX_TIME.withPrefix(getProtocolName()));
}
private static final Pattern PATTERN_ACK = new PatternBuilder()
@@ -65,340 +70,6 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
.text("$").optional()
.compile();
- private static final Pattern PATTERN_INF = new PatternBuilder()
- .text("+").expression("(?:RESP|BUFF):GTINF,")
- .number("[0-9A-Z]{2}xxxx,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("(?:[0-9A-Z]{17},)?") // vin
- .expression("(?:[^,]+)?,") // device name
- .number("(xx),") // state
- .expression("(?:[0-9Ff]{20})?,") // iccid
- .number("(d{1,2}),") // rssi
- .number("d{1,2},")
- .expression("[01]{1,2},") // external power
- .number("([d.]+)?,") // odometer or external power
- .number("d*,") // backup battery or lightness
- .number("(d+.d+),") // battery
- .expression("([01]),") // charging
- .number("(?:d),") // led
- .number("(?:d)?,") // gps on need
- .number("(?:d)?,") // gps antenna type
- .number("(?:d)?,").optional() // gps antenna state
- .number("d{14},") // last fix time
- .groupBegin()
- .number("(d+),") // battery percentage
- .number("[d.]*,") // flash type / power
- .number("(-?[d.]+)?,,,") // temperature
- .or()
- .expression("(?:[01])?,").optional() // pin15 mode
- .number("(d+)?,") // adc1
- .number("(d+)?,").optional() // adc2
- .number("(xx)?,") // digital input
- .number("(xx)?,") // digital output
- .number("[-+]dddd,") // timezone
- .expression("[01],") // daylight saving
- .or()
- .any()
- .groupEnd()
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd),") // time (hhmmss)
- .number("(xxxx)") // counter
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_VER = new PatternBuilder()
- .text("+").expression("(?:RESP|BUFF):GTVER,")
- .number("[0-9A-Z]{2}xxxx,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .expression("([^,]*),") // device type
- .number("(xxxx),") // firmware version
- .number("(xxxx),") // hardware version
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd),") // time (hhmmss)
- .number("(xxxx)") // counter
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_LOCATION = new PatternBuilder()
- .number("(d{1,2}.?d?)?,") // hdop
- .number("(d{1,3}.d)?,") // speed
- .number("(d{1,3}.?d?)?,") // course
- .number("(-?d{1,5}.d)?,") // altitude
- .number("(-?d{1,3}.d{6})?,") // longitude
- .number("(-?d{1,2}.d{6})?,") // latitude
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(d+)?,") // mcc
- .number("(d+)?,") // mnc
- .groupBegin()
- .number("(d+),") // lac
- .number("(d+),") // cid
- .or()
- .number("(x+)?,") // lac
- .number("(x+)?,") // cid
- .groupEnd()
- .number("(?:d+|(d+.d))?,") // rssi / odometer
- .compile();
-
- private static final Pattern PATTERN_OBD = new PatternBuilder()
- .text("+RESP:GTOBD,")
- .number("[0-9A-Z]{2}xxxx,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("(?:[0-9A-Z]{17})?,") // vin
- .expression("[^,]{0,20},") // device name
- .expression("[01],") // report type
- .number("x{1,8},") // report mask
- .expression("(?:[0-9A-Z]{17})?,") // vin
- .number("[01],") // obd connect
- .number("(?:d{1,5})?,") // obd voltage
- .number("(?:x{8})?,") // support pids
- .number("(d{1,5})?,") // engine rpm
- .number("(d{1,3})?,") // speed
- .number("(-?d{1,3})?,") // coolant temp
- .number("(d+.?d*|Inf|NaN)?,") // fuel consumption
- .number("(d{1,5})?,") // dtcs cleared distance
- .number("(?:d{1,5})?,")
- .expression("([01])?,") // obd connect
- .number("(d{1,3})?,") // number of dtcs
- .number("(x*),") // dtcs
- .number("(d{1,3})?,") // throttle
- .number("(?:d{1,3})?,") // engine load
- .number("(d{1,3})?,") // fuel level
- .expression("(?:[0-9A],)?") // obd protocol
- .number("(d+),") // odometer
- .expression(PATTERN_LOCATION.pattern())
- .number("(d{1,7}.d)?,") // odometer
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_FRI = new PatternBuilder()
- .text("+").expression("(?:RESP|BUFF):GT...,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("(?:([0-9A-Z]{17}),)?") // vin
- .expression("[^,]*,") // device name
- .number("(d+)?,") // power
- .number("(d{1,2}),").optional() // report type
- .number("d{1,2},").optional() // count
- .number("d*,").optional() // reserved
- .number("(d+),").optional() // battery
- .expression("((?:")
- .expression(PATTERN_LOCATION.pattern())
- .expression(")+)")
- .groupBegin()
- .number("d{1,2},,")
- .number("(d{1,3}),") // battery
- .number("[01],") // mode
- .number("(?:[01])?,") // motion
- .number("(?:-?d{1,2}.d)?,") // temperature
- .or()
- .number("(d{1,7}.d)?,") // odometer
- .number("(d{5}:dd:dd)?,") // hour meter
- .number("(x+)?,") // adc 1
- .number("(x+)?,") // adc 2
- .number("(d{1,3})?,") // battery
- .number("(?:(xx)(xx)(xx))?,") // device status
- .number("(d+)?,") // rpm
- .number("(?:d+.?d*|Inf|NaN)?,") // fuel consumption
- .number("(d+)?,") // fuel level
- .or()
- .number("(-?d),") // rssi
- .number("(d{1,3}),") // battery
- .or()
- .number("(d{1,7}.d)?,").optional() // odometer
- .number("(d{1,3})?,") // battery
- .groupEnd()
- .any()
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_ERI = new PatternBuilder()
- .text("+").expression("(?:RESP|BUFF):GTERI,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .number("(x{8}),") // mask
- .number("(d+)?,") // power
- .number("d{1,2},") // report type
- .number("d{1,2},") // count
- .expression("((?:")
- .expression(PATTERN_LOCATION.pattern())
- .expression(")+)")
- .groupBegin()
- .number("(d{1,7}.d)?,") // odometer
- .number("(d{5}:dd:dd)?,") // hour meter
- .number("(x+)?,") // adc 1
- .number("(x+)?,").optional() // adc 2
- .groupBegin()
- .number("(x+)?,") // adc 3
- .number("(xx),") // inputs
- .number("(xx),") // outputs
- .or()
- .number("(d{1,3})?,") // battery
- .number("(?:(xx)(xx)(xx))?,") // device status
- .groupEnd()
- .expression("(.*)") // additional data
- .or()
- .number("d*,,")
- .number("(d+),") // battery
- .any()
- .groupEnd()
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_IGN = new PatternBuilder()
- .text("+").expression("(?:RESP|BUFF):GTIG[NF],")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .number("d+,") // ignition off duration
- .expression(PATTERN_LOCATION.pattern())
- .number("(d{5}:dd:dd)?,") // hour meter
- .number("(d{1,7}.d)?,") // odometer
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_LSW = new PatternBuilder()
- .text("+RESP:").expression("GT[LT]SW,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .number("[01],") // type
- .number("([01]),") // state
- .expression(PATTERN_LOCATION.pattern())
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_IDA = new PatternBuilder()
- .text("+RESP:GTIDA,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,,") // device name
- .number("([^,]+),") // rfid
- .expression("[01],") // report type
- .number("1,") // count
- .expression(PATTERN_LOCATION.pattern())
- .number("(d+.d),") // odometer
- .text(",,,,")
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_WIF = new PatternBuilder()
- .text("+RESP:GTWIF,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .number("(d+),") // count
- .number("((?:x{12},-?d+,,,,)+),,,,") // wifi
- .number("(d{1,3}),") // battery
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_GSM = new PatternBuilder()
- .text("+RESP:GTGSM,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("(?:STR|CTN|NMR|RTL),") // fix type
- .expression("(.*)") // cells
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_PNA = new PatternBuilder()
- .text("+RESP:GT").expression("P[NF]A,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN = new PatternBuilder()
- .text("+").expression("(?:RESP|BUFF):GT...,")
- .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
- .number("(d{15}|x{14}),") // imei
- .expression("[^,]*,") // device name
- .number("d*,")
- .number("(x{1,2}),") // report type
- .number("d{1,2},") // count
- .expression(PATTERN_LOCATION.pattern())
- .groupBegin()
- .number("(d{1,7}.d)?,").optional() // odometer
- .number("(d{1,3})?,") // battery
- .or()
- .number("(d{1,7}.d)?,") // odometer
- .groupEnd()
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)") // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
- private static final Pattern PATTERN_BASIC = new PatternBuilder()
- .text("+").expression("(?:RESP|BUFF)").text(":")
- .expression("GT...,")
- .number("(?:[0-9A-Z]{2}xxxx)?,").optional() // protocol version
- .number("(d{15}|x{14}),") // imei
- .any()
- .text(",")
- .number("(d{1,2})?,") // hdop
- .number("(d{1,3}.d)?,") // speed
- .number("(d{1,3})?,") // course
- .number("(-?d{1,5}.d)?,") // altitude
- .number("(-?d{1,3}.d{6})?,") // longitude
- .number("(-?d{1,2}.d{6})?,") // latitude
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(d+),") // mcc
- .number("(d+),") // mnc
- .number("(x+),") // lac
- .number("(x+),").optional(4) // cell
- .any()
- .number("(dddd)(dd)(dd)") // date (yyyymmdd)
- .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
- .text(",")
- .number("(xxxx)") // count number
- .text("$").optional()
- .compile();
-
private Object decodeAck(Channel channel, SocketAddress remoteAddress, String sentence, String type) {
Parser parser = new Parser(PATTERN_ACK, sentence);
if (parser.matches()) {
@@ -450,13 +121,54 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
private Long parseHours(String hoursString) {
if (hoursString != null) {
String[] hours = hoursString.split(":");
- return (long) (Integer.parseInt(hours[0]) * 3600
- + (hours.length > 1 ? Integer.parseInt(hours[1]) * 60 : 0)
+ return (Integer.parseInt(hours[0]) * 3600L
+ + (hours.length > 1 ? Integer.parseInt(hours[1]) * 60L : 0)
+ (hours.length > 2 ? Integer.parseInt(hours[2]) : 0)) * 1000;
}
return null;
}
+ private static final Pattern PATTERN_INF = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF):GTINF,")
+ .number("[0-9A-Z]{2}xxxx,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("(?:[0-9A-Z]{17},)?") // vin
+ .expression("(?:[^,]+)?,") // device name
+ .number("(xx),") // state
+ .expression("(?:[0-9Ff]{20})?,") // iccid
+ .number("(d{1,2}),") // rssi
+ .number("d{1,2},")
+ .expression("[01]{1,2},") // external power
+ .number("([d.]+)?,") // odometer or external power
+ .number("d*,") // backup battery or lightness
+ .number("(d+.d+),") // battery
+ .expression("([01]),") // charging
+ .number("(?:d),") // led
+ .number("(?:d)?,") // gps on need
+ .number("(?:d)?,") // gps antenna type
+ .number("(?:d)?,").optional() // gps antenna state
+ .number("d{14},") // last fix time
+ .groupBegin()
+ .number("(d+),") // battery percentage
+ .number("[d.]*,") // flash type / power
+ .number("(-?[d.]+)?,,,") // temperature
+ .or()
+ .expression("(?:[01])?,").optional() // pin15 mode
+ .number("(d+)?,") // adc1
+ .number("(d+)?,").optional() // adc2
+ .number("(xx)?,") // digital input
+ .number("(xx)?,") // digital output
+ .number("[-+]dddd,") // timezone
+ .expression("[01],") // daylight saving
+ .or()
+ .any()
+ .groupEnd()
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .number("(xxxx)") // counter
+ .text("$").optional()
+ .compile();
+
private Object decodeInf(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_INF, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -517,6 +229,20 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_VER = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF):GTVER,")
+ .number("[0-9A-Z]{2}xxxx,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .expression("([^,]*),") // device type
+ .number("(xxxx),") // firmware version
+ .number("(xxxx),") // hardware version
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .number("(xxxx)") // counter
+ .text("$").optional()
+ .compile();
+
private Object decodeVer(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_VER, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -537,6 +263,28 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
parser.skip(19);
}
+ private static final Pattern PATTERN_LOCATION = new PatternBuilder()
+ .number("(d{1,2}.?d?)?,") // hdop
+ .number("(d{1,3}.d)?,") // speed
+ .number("(d{1,3}.?d?)?,") // course
+ .number("(-?d{1,5}.d)?,") // altitude
+ .number("(-?d{1,3}.d{6})?,") // longitude
+ .number("(-?d{1,2}.d{6})?,") // latitude
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(d+)?,") // mcc
+ .number("(d+)?,") // mnc
+ .groupBegin()
+ .number("(d+),") // lac
+ .number("(d+),") // cid
+ .or()
+ .number("(x+)?,") // lac
+ .number("(x+)?,") // cid
+ .groupEnd()
+ .number("(?:d+|(d+.d))?,") // rssi / odometer
+ .compile();
+
private void decodeLocation(Position position, Parser parser) {
Double hdop = parser.nextDouble();
position.setValid(hdop == null || hdop > 0);
@@ -571,6 +319,41 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
}
}
+ private static final Pattern PATTERN_OBD = new PatternBuilder()
+ .text("+RESP:GTOBD,")
+ .number("[0-9A-Z]{2}xxxx,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("(?:[0-9A-Z]{17})?,") // vin
+ .expression("[^,]{0,20},") // device name
+ .expression("[01],") // report type
+ .number("x{1,8},") // report mask
+ .expression("(?:[0-9A-Z]{17})?,") // vin
+ .number("[01],") // obd connect
+ .number("(?:d{1,5})?,") // obd voltage
+ .number("(?:x{8})?,") // support pids
+ .number("(d{1,5})?,") // engine rpm
+ .number("(d{1,3})?,") // speed
+ .number("(-?d{1,3})?,") // coolant temp
+ .number("(d+.?d*|Inf|NaN)?,") // fuel consumption
+ .number("(d{1,5})?,") // dtcs cleared distance
+ .number("(?:d{1,5})?,")
+ .expression("([01])?,") // obd connect
+ .number("(d{1,3})?,") // number of dtcs
+ .number("(x*),") // dtcs
+ .number("(d{1,3})?,") // throttle
+ .number("(?:d{1,3})?,") // engine load
+ .number("(d{1,3})?,") // fuel level
+ .expression("(?:[0-9A],)?") // obd protocol
+ .number("(d+),") // odometer
+ .expression(PATTERN_LOCATION.pattern())
+ .number("(d{1,7}.d)?,") // odometer
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeObd(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_OBD, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -617,7 +400,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[index++]);
position.setDeviceId(deviceSession.getDeviceId());
- index += 1; // device name
+ String deviceName = values[index++];
index += 1; // report type
index += 1; // canbus state
long reportMask = Long.parseLong(values[index++], 16);
@@ -659,11 +442,11 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
if (BitUtil.check(reportMask, 11) && !values[index++].isEmpty()) {
position.set(Position.KEY_HOURS, UnitsConverter.msFromHours(Double.parseDouble(values[index - 1])));
}
- if (BitUtil.check(reportMask, 12)) {
- position.set("drivingHours", Double.parseDouble(values[index++]));
+ if (BitUtil.check(reportMask, 12) && !values[index++].isEmpty()) {
+ position.set(Position.KEY_DRIVING_TIME, Double.parseDouble(values[index - 1]));
}
- if (BitUtil.check(reportMask, 13)) {
- position.set("idleHours", Double.parseDouble(values[index++]));
+ if (BitUtil.check(reportMask, 13) && !values[index++].isEmpty()) {
+ position.set("idleHours", Double.parseDouble(values[index - 1]));
}
if (BitUtil.check(reportMask, 14) && !values[index++].isEmpty()) {
position.set("idleFuelConsumption", Double.parseDouble(values[index - 1]));
@@ -689,8 +472,19 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
if (BitUtil.check(reportMask, 21) && !values[index++].isEmpty()) {
position.set("engineOverspeed", Double.parseDouble(values[index - 1]));
}
- if (BitUtil.check(reportMask, 29)) {
- reportMaskExt = Long.parseLong(values[index++], 16);
+ if ("GV350M".equals(deviceName)) {
+ if (BitUtil.check(reportMask, 22)) {
+ index += 1; // impulse distance
+ }
+ if (BitUtil.check(reportMask, 23)) {
+ index += 1; // gross vehicle weight
+ }
+ if (BitUtil.check(reportMask, 24)) {
+ index += 1; // catalyst liquid level
+ }
+ }
+ if (BitUtil.check(reportMask, 29) && !values[index++].isEmpty()) {
+ reportMaskExt = Long.parseLong(values[index - 1], 16);
}
if (BitUtil.check(reportMaskExt, 0) && !values[index++].isEmpty()) {
position.set("adBlueLevel", Integer.parseInt(values[index - 1]));
@@ -821,6 +615,51 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
}
}
+ private static final Pattern PATTERN_FRI = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF):GT...,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("(?:([0-9A-Z]{17}),)?") // vin
+ .expression("[^,]*,") // device name
+ .number("(d+)?,") // power
+ .number("(d{1,2}),").optional() // report type
+ .number("d{1,2},").optional() // count
+ .number("d*,").optional() // reserved
+ .number("(d+),").optional() // battery
+ .expression("((?:")
+ .expression(PATTERN_LOCATION.pattern())
+ .expression(")+)")
+ .groupBegin()
+ .number("d{1,2},,")
+ .number("(d{1,3}),") // battery
+ .number("[01],") // mode
+ .number("(?:[01])?,") // motion
+ .number("(?:-?d{1,2}.d)?,") // temperature
+ .or()
+ .number("(d{1,7}.d)?,") // odometer
+ .number("(d{5}:dd:dd)?,") // hour meter
+ .number("(x+)?,") // adc 1
+ .number("(x+)?,") // adc 2
+ .number("(d{1,3})?,") // battery
+ .number("(?:(xx)(xx)(xx))?,") // device status
+ .number("(d+)?,") // rpm
+ .number("(?:d+.?d*|Inf|NaN)?,") // fuel consumption
+ .number("(d+)?,") // fuel level
+ .or()
+ .number("(-?d),") // rssi
+ .number("(d{1,3}),") // battery
+ .or()
+ .number("(d{1,7}.d)?,").optional() // odometer
+ .number("(d{1,3})?,") // battery
+ .groupEnd()
+ .any()
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeFri(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_FRI, sentence);
if (!parser.matches()) {
@@ -901,6 +740,44 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return positions;
}
+ private static final Pattern PATTERN_ERI = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF):GTERI,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("(x{8}),") // mask
+ .number("(d+)?,") // power
+ .number("d{1,2},") // report type
+ .number("d{1,2},") // count
+ .expression("((?:")
+ .expression(PATTERN_LOCATION.pattern())
+ .expression(")+)")
+ .groupBegin()
+ .number("(d{1,7}.d)?,") // odometer
+ .number("(d{5}:dd:dd)?,") // hour meter
+ .number("(x+)?,") // adc 1
+ .number("(x+)?,").optional() // adc 2
+ .groupBegin()
+ .number("(x+)?,") // adc 3
+ .number("(xx),") // inputs
+ .number("(xx),") // outputs
+ .or()
+ .number("(d{1,3})?,") // battery
+ .number("(?:(xx)(xx)(xx))?,") // device status
+ .groupEnd()
+ .expression("(.*)") // additional data
+ .or()
+ .number("d*,,")
+ .number("(d+),") // battery
+ .any()
+ .groupEnd()
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeEri(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_ERI, sentence);
if (!parser.matches()) {
@@ -936,7 +813,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_POWER, power * 0.001);
}
- if (parser.hasNext(12)) {
+ if (parser.hasNextAny(12)) {
position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
position.set(Position.KEY_HOURS, parseHours(parser.next()));
@@ -958,7 +835,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
index += 1; // device type
if (BitUtil.check(mask, 0)) {
- index += 1; // digital fuel sensor data
+ position.set(Position.KEY_FUEL_LEVEL, Integer.parseInt(data[index++], 16));
}
if (BitUtil.check(mask, 1)) {
@@ -1004,6 +881,22 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return positions;
}
+ private static final Pattern PATTERN_IGN = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF):GTIG[NF],")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("d+,") // ignition off duration
+ .expression(PATTERN_LOCATION.pattern())
+ .number("(d{5}:dd:dd)?,") // hour meter
+ .number("(d{1,7}.d)?,") // odometer
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeIgn(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_IGN, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1022,6 +915,21 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_LSW = new PatternBuilder()
+ .text("+RESP:").expression("GT[LT]SW,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("[01],") // type
+ .number("([01]),") // state
+ .expression(PATTERN_LOCATION.pattern())
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeLsw(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_LSW, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1038,6 +946,24 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_IDA = new PatternBuilder()
+ .text("+RESP:GTIDA,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,,") // device name
+ .number("([^,]+),") // rfid
+ .expression("[01],") // report type
+ .number("1,") // count
+ .expression(PATTERN_LOCATION.pattern())
+ .number("(d+.d),") // odometer
+ .text(",,,,")
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeIda(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_IDA, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1056,6 +982,21 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_WIF = new PatternBuilder()
+ .text("+RESP:GTWIF,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("(d+),") // count
+ .number("((?:x{12},-?d+,,,,)+),,,,") // wifi
+ .number("(d{1,3}),") // battery
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeWif(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_WIF, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1082,6 +1023,19 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_GSM = new PatternBuilder()
+ .text("+RESP:GTGSM,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("(?:STR|CTN|NMR|RTL),") // fix type
+ .expression("(.*)") // cells
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeGsm(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_GSM, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1108,6 +1062,18 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_PNA = new PatternBuilder()
+ .text("+RESP:GT").expression("P[NF]A,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodePna(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_PNA, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1122,6 +1088,204 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_DAR = new PatternBuilder()
+ .text("+RESP:GTDAR,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("(d),") // warning type
+ .number("(d{1,2}),,,") // fatigue degree
+ .expression(PATTERN_LOCATION.pattern())
+ .any()
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
+ private Object decodeDar(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_DAR, sentence);
+ Position position = initPosition(parser, channel, remoteAddress);
+ if (position == null) {
+ return null;
+ }
+
+ int warningType = parser.nextInt();
+ int fatigueDegree = parser.nextInt();
+ if (warningType == 1) {
+ position.set(Position.KEY_ALARM, Position.ALARM_FATIGUE_DRIVING);
+ position.set("fatigueDegree", fatigueDegree);
+ } else {
+ position.set("warningType", warningType);
+ }
+
+ decodeLocation(position, parser);
+
+ decodeDeviceTime(position, parser);
+
+ return position;
+ }
+
+ private static final Pattern PATTERN_DTT = new PatternBuilder()
+ .text("+RESP:GTDTT,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,,,") // device name
+ .number("d,") // data type
+ .number("d+,") // data length
+ .number("(x+),") // data
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
+ private Object decodeDtt(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_DTT, sentence);
+ Position position = initPosition(parser, channel, remoteAddress);
+ if (position == null) {
+ return null;
+ }
+
+ getLastLocation(position, null);
+
+ String data = Unpooled.wrappedBuffer(DataConverter.parseHex(parser.next()))
+ .toString(StandardCharsets.US_ASCII);
+ if (data.contains("COMB")) {
+ String[] values = data.split(",");
+ position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(values[2]));
+ } else {
+ position.set(Position.KEY_RESULT, data);
+ }
+
+ decodeDeviceTime(position, parser);
+
+ return position;
+ }
+
+ private static final Pattern PATTERN_BAA = new PatternBuilder()
+ .text("+RESP:GTBAA,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("x+,") // index
+ .number("d,") // accessory type
+ .number("d,") // accessory model
+ .number("x+,") // alarm type
+ .number("(x{4}),") // append mask
+ .expression("((?:[^,]+,){0,6})") // accessory optionals
+ .expression(PATTERN_LOCATION.pattern())
+ .any()
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
+ private Object decodeBaa(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_BAA, sentence);
+ Position position = initPosition(parser, channel, remoteAddress);
+ if (position == null) {
+ return null;
+ }
+
+ int mask = parser.nextHexInt();
+ String[] values = parser.next().split(",");
+ int index = 0;
+ if (BitUtil.check(mask, 0)) {
+ position.set("accessoryName", values[index++]);
+ }
+ if (BitUtil.check(mask, 1)) {
+ position.set("accessoryMac", values[index++]);
+ }
+ if (BitUtil.check(mask, 2)) {
+ position.set("accessoryStatus", Integer.parseInt(values[index++]));
+ }
+ if (BitUtil.check(mask, 3)) {
+ position.set("accessoryVoltage", Integer.parseInt(values[index++]) * 0.001);
+ }
+ if (BitUtil.check(mask, 4)) {
+ position.set("accessoryTemp", Integer.parseInt(values[index++]));
+ }
+ if (BitUtil.check(mask, 5)) {
+ position.set("accessoryHumidity", Integer.parseInt(values[index]));
+ }
+
+ decodeLocation(position, parser);
+
+ decodeDeviceTime(position, parser);
+
+ return position;
+ }
+
+ private static final Pattern PATTERN_BID = new PatternBuilder()
+ .text("+RESP:GTBID,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("d,") // count
+ .number("d,") // accessory model
+ .number("(x{4}),") // append mask
+ .expression("((?:[^,]+,){0,2})") // accessory optionals
+ .expression(PATTERN_LOCATION.pattern())
+ .any()
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
+ private Object decodeBid(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_BID, sentence);
+ Position position = initPosition(parser, channel, remoteAddress);
+ if (position == null) {
+ return null;
+ }
+
+ int mask = parser.nextHexInt();
+ String[] values = parser.next().split(",");
+ int index = 0;
+ if (BitUtil.check(mask, 1)) {
+ position.set("accessoryMac", values[index++]);
+ }
+ if (BitUtil.check(mask, 3)) {
+ position.set("accessoryVoltage", Integer.parseInt(values[index]) * 0.001);
+ }
+
+ decodeLocation(position, parser);
+
+ decodeDeviceTime(position, parser);
+
+ return position;
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF):GT...,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .expression("[^,]*,") // device name
+ .number("d*,")
+ .number("(x{1,2}),") // report type
+ .number("d{1,2},") // count
+ .number("d*,").optional() // reserved
+ .expression(PATTERN_LOCATION.pattern())
+ .groupBegin()
+ .number("(?:(d{1,7}.d)|0)?,").optional() // odometer
+ .number("(d{1,3})?,") // battery
+ .or()
+ .number("(d{1,7}.d)?,") // odometer
+ .groupEnd()
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)") // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeOther(Channel channel, SocketAddress remoteAddress, String sentence, String type) {
Parser parser = new Parser(PATTERN, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1172,6 +1336,34 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_BASIC = new PatternBuilder()
+ .text("+").expression("(?:RESP|BUFF)").text(":")
+ .expression("GT...,")
+ .number("(?:[0-9A-Z]{2}xxxx)?,").optional() // protocol version
+ .number("(d{15}|x{14}),") // imei
+ .any()
+ .text(",")
+ .number("(d{1,2})?,") // hdop
+ .number("(d{1,3}.d)?,") // speed
+ .number("(d{1,3})?,") // course
+ .number("(-?d{1,5}.d)?,") // altitude
+ .number("(-?d{1,3}.d{6})?,") // longitude
+ .number("(-?d{1,2}.d{6})?,") // latitude
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(d+),") // mcc
+ .number("(d+),") // mnc
+ .number("(x+),") // lac
+ .number("(x+),").optional(4) // cell
+ .any()
+ .number("(dddd)(dd)(dd)") // date (yyyymmdd)
+ .number("(dd)(dd)(dd)").optional(2) // time (hhmmss)
+ .text(",")
+ .number("(xxxx)") // count number
+ .text("$").optional()
+ .compile();
+
private Object decodeBasic(Channel channel, SocketAddress remoteAddress, String sentence, String type) {
Parser parser = new Parser(PATTERN_BASIC, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1313,6 +1505,18 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
case "PFA":
result = decodePna(channel, remoteAddress, sentence);
break;
+ case "DAR":
+ result = decodeDar(channel, remoteAddress, sentence);
+ break;
+ case "DTT":
+ result = decodeDtt(channel, remoteAddress, sentence);
+ break;
+ case "BAA":
+ result = decodeBaa(channel, remoteAddress, sentence);
+ break;
+ case "BID":
+ result = decodeBid(channel, remoteAddress, sentence);
+ break;
default:
result = decodeOther(channel, remoteAddress, sentence, type);
break;
@@ -1333,7 +1537,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
}
}
- if (channel != null && Context.getConfig().getBoolean(Keys.PROTOCOL_ACK.withPrefix(getProtocolName()))) {
+ if (channel != null && getConfig().getBoolean(Keys.PROTOCOL_ACK.withPrefix(getProtocolName()))) {
String checksum;
if (sentence.endsWith("$")) {
checksum = sentence.substring(sentence.length() - 1 - 4, sentence.length() - 1);
diff --git a/src/main/java/org/traccar/protocol/GlobalSatProtocol.java b/src/main/java/org/traccar/protocol/GlobalSatProtocol.java
index e86b5dc30..13f4f2646 100644
--- a/src/main/java/org/traccar/protocol/GlobalSatProtocol.java
+++ b/src/main/java/org/traccar/protocol/GlobalSatProtocol.java
@@ -21,18 +21,22 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class GlobalSatProtocol extends BaseProtocol {
- public GlobalSatProtocol() {
+ @Inject
+ public GlobalSatProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_ALARM_DISMISS,
Command.TYPE_OUTPUT_CONTROL);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "!\r\n", "!"));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/GlobalSatProtocolDecoder.java b/src/main/java/org/traccar/protocol/GlobalSatProtocolDecoder.java
index b48df4047..720b61695 100644
--- a/src/main/java/org/traccar/protocol/GlobalSatProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GlobalSatProtocolDecoder.java
@@ -17,8 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -40,9 +39,12 @@ public class GlobalSatProtocolDecoder extends BaseProtocolDecoder {
public GlobalSatProtocolDecoder(Protocol protocol) {
super(protocol);
+ }
- format0 = Context.getConfig().getString(getProtocolName() + ".format0", "TSPRXAB27GHKLMnaicz*U!");
- format1 = Context.getConfig().getString(getProtocolName() + ".format1", "SARY*U!");
+ @Override
+ protected void init() {
+ format0 = getConfig().getString(getProtocolName() + ".format0", "TSPRXAB27GHKLMnaicz*U!");
+ format1 = getConfig().getString(getProtocolName() + ".format1", "SARY*U!");
}
public void setFormat0(String format) {
diff --git a/src/main/java/org/traccar/protocol/GlobalstarProtocol.java b/src/main/java/org/traccar/protocol/GlobalstarProtocol.java
index 84cd5565b..1d9b6b6dd 100644
--- a/src/main/java/org/traccar/protocol/GlobalstarProtocol.java
+++ b/src/main/java/org/traccar/protocol/GlobalstarProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class GlobalstarProtocol extends BaseProtocol {
- public GlobalstarProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public GlobalstarProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(65535));
diff --git a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java
index b742d0cac..0ddb95c14 100644
--- a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java
@@ -27,7 +27,7 @@ import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -151,15 +151,11 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder {
position.setCourse(BitUtil.from(flags, 5) * 45);
- position.setLatitude(buf.readUnsignedMedium() * 90.0 / (1 << 23));
- if (position.getLatitude() > 90) {
- position.setLatitude(position.getLatitude() - 180);
- }
+ double latitude = buf.readUnsignedMedium() * 90.0 / (1 << 23);
+ position.setLatitude(latitude > 90 ? latitude - 180 : latitude);
- position.setLongitude(buf.readUnsignedMedium() * 180.0 / (1 << 23));
- if (position.getLongitude() > 180) {
- position.setLongitude(position.getLongitude() - 360);
- }
+ double longitude = buf.readUnsignedMedium() * 180.0 / (1 << 23);
+ position.setLongitude(longitude > 180 ? longitude - 360 : longitude);
int speed = buf.readUnsignedByte();
position.setSpeed(UnitsConverter.knotsFromKph(speed));
diff --git a/src/main/java/org/traccar/protocol/GnxProtocol.java b/src/main/java/org/traccar/protocol/GnxProtocol.java
index 3576bf805..cfa496009 100644
--- a/src/main/java/org/traccar/protocol/GnxProtocol.java
+++ b/src/main/java/org/traccar/protocol/GnxProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class GnxProtocol extends BaseProtocol {
- public GnxProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public GnxProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\n\r"));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/GnxProtocolDecoder.java b/src/main/java/org/traccar/protocol/GnxProtocolDecoder.java
index c9c221a69..9c8b6879a 100644
--- a/src/main/java/org/traccar/protocol/GnxProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GnxProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/GoSafeProtocol.java b/src/main/java/org/traccar/protocol/GoSafeProtocol.java
index aaaffac97..c9c0456a0 100644
--- a/src/main/java/org/traccar/protocol/GoSafeProtocol.java
+++ b/src/main/java/org/traccar/protocol/GoSafeProtocol.java
@@ -21,22 +21,26 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class GoSafeProtocol extends BaseProtocol {
- public GoSafeProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public GoSafeProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new GoSafeProtocolDecoder(GoSafeProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new GoSafeProtocolDecoder(GoSafeProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java b/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java
index a86249224..f17ea0e08 100644
--- a/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GoSafeProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -93,14 +93,14 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder {
position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(values[index - 1])));
}
position.setCourse(Integer.parseInt(values[index++]));
- if (index < values.length) {
- position.setAltitude(Integer.parseInt(values[index++]));
+ if (index < values.length && !values[index++].isEmpty()) {
+ position.setAltitude(Integer.parseInt(values[index - 1]));
}
- if (index < values.length) {
- position.set(Position.KEY_HDOP, Double.parseDouble(values[index++]));
+ if (index < values.length && !values[index++].isEmpty()) {
+ position.set(Position.KEY_HDOP, Double.parseDouble(values[index - 1]));
}
- if (index < values.length) {
- position.set(Position.KEY_VDOP, Double.parseDouble(values[index++]));
+ if (index < values.length && !values[index++].isEmpty()) {
+ position.set(Position.KEY_VDOP, Double.parseDouble(values[index - 1]));
}
break;
case "GSM":
diff --git a/src/main/java/org/traccar/protocol/GotopProtocol.java b/src/main/java/org/traccar/protocol/GotopProtocol.java
index 07fe02248..21fbbae99 100644
--- a/src/main/java/org/traccar/protocol/GotopProtocol.java
+++ b/src/main/java/org/traccar/protocol/GotopProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class GotopProtocol extends BaseProtocol {
- public GotopProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public GotopProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#'));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/GotopProtocolDecoder.java b/src/main/java/org/traccar/protocol/GotopProtocolDecoder.java
index a867451aa..5c8d0bac2 100644
--- a/src/main/java/org/traccar/protocol/GotopProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GotopProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 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,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
@@ -35,7 +35,7 @@ public class GotopProtocolDecoder extends BaseProtocolDecoder {
private static final Pattern PATTERN = new PatternBuilder()
.number("(d+),") // imei
- .expression("[^,]+,") // type
+ .expression("([^,]+),") // type
.expression("([AV]),") // validity
.number("DATE:(dd)(dd)(dd),") // date (yyddmm)
.number("TIME:(dd)(dd)(dd),") // time (hhmmss)
@@ -56,14 +56,25 @@ public class GotopProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- Position position = new Position(getProtocolName());
-
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
if (deviceSession == null) {
return null;
}
+
+ Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
+ String type = parser.next();
+ if (type.equals("CMD-KEY")) {
+ position.set(Position.KEY_ALARM, Position.ALARM_SOS);
+ } else if (type.startsWith("ALM-B")) {
+ if (Character.getNumericValue(type.charAt(5)) % 2 > 0) {
+ position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_ENTER);
+ } else {
+ position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE_EXIT);
+ }
+ }
+
position.setValid(parser.next().equals("A"));
position.setTime(parser.nextDateTime());
diff --git a/src/main/java/org/traccar/protocol/Gps056Protocol.java b/src/main/java/org/traccar/protocol/Gps056Protocol.java
index b6ab10a19..44fc392be 100644
--- a/src/main/java/org/traccar/protocol/Gps056Protocol.java
+++ b/src/main/java/org/traccar/protocol/Gps056Protocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Gps056Protocol extends BaseProtocol {
- public Gps056Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Gps056Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new Gps056FrameDecoder());
pipeline.addLast(new Gps056ProtocolDecoder(Gps056Protocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/Gps056ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gps056ProtocolDecoder.java
index 0ba79bb51..eea64364e 100644
--- a/src/main/java/org/traccar/protocol/Gps056ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gps056ProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/Gps103Protocol.java b/src/main/java/org/traccar/protocol/Gps103Protocol.java
index 5356387ce..8424abfe5 100644
--- a/src/main/java/org/traccar/protocol/Gps103Protocol.java
+++ b/src/main/java/org/traccar/protocol/Gps103Protocol.java
@@ -21,11 +21,15 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class Gps103Protocol extends BaseProtocol {
- public Gps103Protocol() {
+ @Inject
+ public Gps103Protocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_POSITION_SINGLE,
@@ -36,9 +40,9 @@ public class Gps103Protocol extends BaseProtocol {
Command.TYPE_ALARM_ARM,
Command.TYPE_ALARM_DISARM,
Command.TYPE_REQUEST_PHOTO);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(2048, false, "\r\n", "\n", ";", "*"));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
@@ -46,9 +50,9 @@ public class Gps103Protocol extends BaseProtocol {
pipeline.addLast(new Gps103ProtocolDecoder(Gps103Protocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new Gps103ProtocolEncoder(Gps103Protocol.this));
diff --git a/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java
index d74f19179..d1c35b478 100644
--- a/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java
@@ -19,8 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DataConverter;
@@ -57,9 +56,12 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
.groupEnd()
.expression("([^,]+)?,") // rfid
.groupBegin()
- .text("L,,,")
+ .text("L,")
+ .groupBegin()
+ .text(",,")
.number("(x+),,") // lac
.number("(x+),,,") // cid
+ .groupEnd("?")
.or()
.text("F,")
.groupBegin()
@@ -203,7 +205,7 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.PREFIX_TEMP + 1, Double.parseDouble(alarm.substring(2)));
} else if (alarm.startsWith("oil ")) {
position.set(Position.KEY_FUEL_LEVEL, Double.parseDouble(alarm.substring(4)));
- } else if (!position.getAttributes().containsKey(Position.KEY_ALARM) && !alarm.equals("tracker")) {
+ } else if (!position.hasAttribute(Position.KEY_ALARM) && !alarm.equals("tracker")) {
position.set(Position.KEY_EVENT, alarm);
}
@@ -219,12 +221,11 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
}
if (parser.hasNext(2)) {
+ position.setNetwork(new Network(CellTower.fromLacCid(
+ getConfig(), parser.nextHexInt(0), parser.nextHexInt(0))));
+ }
- getLastLocation(position, null);
-
- position.setNetwork(new Network(CellTower.fromLacCid(parser.nextHexInt(0), parser.nextHexInt(0))));
-
- } else {
+ if (parser.hasNextAny(20)) {
String utcHours = parser.next();
String utcMinutes = parser.next();
@@ -262,6 +263,10 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
position.set("fuel2", parser.nextDouble());
position.set(Position.PREFIX_TEMP + 1, parser.nextInt());
+ } else {
+
+ getLastLocation(position, null);
+
}
return position;
@@ -361,7 +366,7 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder {
getLastLocation(position, null);
try {
- position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(imei, photo, "jpg"));
+ position.set(Position.KEY_IMAGE, writeMediaFile(imei, photo, "jpg"));
} finally {
photoPackets = 0;
photo.release();
diff --git a/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java
index e662e9b04..9a899eeeb 100644
--- a/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/Gps103ProtocolEncoder.java
@@ -49,7 +49,7 @@ public class Gps103ProtocolEncoder extends StringProtocolEncoder implements Stri
case Command.TYPE_CUSTOM:
return formatCommand(command, "**,imei:%s,%s", Command.KEY_UNIQUE_ID, Command.KEY_DATA);
case Command.TYPE_POSITION_STOP:
- return formatCommand(command, "**,imei:%s,A", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "**,imei:%s,D", Command.KEY_UNIQUE_ID);
case Command.TYPE_POSITION_SINGLE:
return formatCommand(command, "**,imei:%s,B", Command.KEY_UNIQUE_ID);
case Command.TYPE_POSITION_PERIODIC:
diff --git a/src/main/java/org/traccar/protocol/GpsGateProtocol.java b/src/main/java/org/traccar/protocol/GpsGateProtocol.java
index a131b6f48..db1e8554a 100644
--- a/src/main/java/org/traccar/protocol/GpsGateProtocol.java
+++ b/src/main/java/org/traccar/protocol/GpsGateProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class GpsGateProtocol extends BaseProtocol {
- public GpsGateProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public GpsGateProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\0", "\n", "\r\n"));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/GpsGateProtocolDecoder.java b/src/main/java/org/traccar/protocol/GpsGateProtocolDecoder.java
index c158d3212..82da58f1e 100644
--- a/src/main/java/org/traccar/protocol/GpsGateProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GpsGateProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Checksum;
diff --git a/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java b/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java
index ad23ece48..f50088b2b 100644
--- a/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java
+++ b/src/main/java/org/traccar/protocol/GpsMarkerProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class GpsMarkerProtocol extends BaseProtocol {
- public GpsMarkerProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public GpsMarkerProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\r"));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/GpsMarkerProtocolDecoder.java b/src/main/java/org/traccar/protocol/GpsMarkerProtocolDecoder.java
index bbb2c31e2..0fef4b7da 100644
--- a/src/main/java/org/traccar/protocol/GpsMarkerProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GpsMarkerProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/GpsmtaProtocol.java b/src/main/java/org/traccar/protocol/GpsmtaProtocol.java
index ce6cc5929..e146a816d 100644
--- a/src/main/java/org/traccar/protocol/GpsmtaProtocol.java
+++ b/src/main/java/org/traccar/protocol/GpsmtaProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class GpsmtaProtocol extends BaseProtocol {
- public GpsmtaProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public GpsmtaProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new GpsmtaProtocolDecoder(GpsmtaProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/GpsmtaProtocolDecoder.java b/src/main/java/org/traccar/protocol/GpsmtaProtocolDecoder.java
index 31f9401b4..a9b85d255 100644
--- a/src/main/java/org/traccar/protocol/GpsmtaProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GpsmtaProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/GranitProtocol.java b/src/main/java/org/traccar/protocol/GranitProtocol.java
index 244c3977b..9ca0fe25e 100644
--- a/src/main/java/org/traccar/protocol/GranitProtocol.java
+++ b/src/main/java/org/traccar/protocol/GranitProtocol.java
@@ -19,11 +19,15 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class GranitProtocol extends BaseProtocol {
- public GranitProtocol() {
+ @Inject
+ public GranitProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_IDENTIFICATION,
Command.TYPE_REBOOT_DEVICE,
@@ -32,9 +36,9 @@ public class GranitProtocol extends BaseProtocol {
setSupportedTextCommands(
Command.TYPE_REBOOT_DEVICE,
Command.TYPE_POSITION_PERIODIC);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new GranitFrameDecoder());
pipeline.addLast(new GranitProtocolEncoder(GranitProtocol.this));
pipeline.addLast(new GranitProtocolDecoder(GranitProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/GranitProtocolDecoder.java b/src/main/java/org/traccar/protocol/GranitProtocolDecoder.java
index 292e43a0e..dfc3c10f6 100644
--- a/src/main/java/org/traccar/protocol/GranitProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/GranitProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/Gs100Protocol.java b/src/main/java/org/traccar/protocol/Gs100Protocol.java
index a701815d0..715d48fc4 100644
--- a/src/main/java/org/traccar/protocol/Gs100Protocol.java
+++ b/src/main/java/org/traccar/protocol/Gs100Protocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Gs100Protocol extends BaseProtocol {
- public Gs100Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Gs100Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new Gs100ProtocolDecoder(Gs100Protocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/Gs100ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gs100ProtocolDecoder.java
index 2496aad48..352070107 100644
--- a/src/main/java/org/traccar/protocol/Gs100ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gs100ProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BcdUtil;
diff --git a/src/main/java/org/traccar/protocol/Gt02Protocol.java b/src/main/java/org/traccar/protocol/Gt02Protocol.java
index f412ee720..f448feacc 100644
--- a/src/main/java/org/traccar/protocol/Gt02Protocol.java
+++ b/src/main/java/org/traccar/protocol/Gt02Protocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Gt02Protocol extends BaseProtocol {
- public Gt02Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Gt02Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 1, 2, 0));
pipeline.addLast(new Gt02ProtocolDecoder(Gt02Protocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/Gt02ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt02ProtocolDecoder.java
index 78a3fd3ee..4ecb0b43b 100644
--- a/src/main/java/org/traccar/protocol/Gt02ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gt02ProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/Gt06Protocol.java b/src/main/java/org/traccar/protocol/Gt06Protocol.java
index 9ec8de098..945ec3831 100644
--- a/src/main/java/org/traccar/protocol/Gt06Protocol.java
+++ b/src/main/java/org/traccar/protocol/Gt06Protocol.java
@@ -18,18 +18,22 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class Gt06Protocol extends BaseProtocol {
- public Gt06Protocol() {
+ @Inject
+ public Gt06Protocol(Config config) {
setSupportedDataCommands(
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME,
Command.TYPE_CUSTOM);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new Gt06FrameDecoder());
pipeline.addLast(new Gt06ProtocolEncoder(Gt06Protocol.this));
pipeline.addLast(new Gt06ProtocolDecoder(Gt06Protocol.this));
diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java
index feacc1ae8..161d04d8d 100644
--- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
-Supp * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,8 +20,8 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.helper.BufferUtil;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BcdUtil;
@@ -32,7 +32,6 @@ import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.CellTower;
-import org.traccar.model.Device;
import org.traccar.model.Network;
import org.traccar.model.Position;
import org.traccar.model.WifiAccessPoint;
@@ -75,15 +74,16 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_LBS_EXTEND = 0x18;
public static final int MSG_LBS_STATUS = 0x19;
public static final int MSG_GPS_PHONE = 0x1A;
- public static final int MSG_GPS_LBS_EXTEND = 0x1E;
- public static final int MSG_HEARTBEAT = 0x23;
- public static final int MSG_ADDRESS_REQUEST = 0x2A;
- public static final int MSG_ADDRESS_RESPONSE = 0x97;
- public static final int MSG_GPS_LBS_5 = 0x31;
- public static final int MSG_GPS_LBS_STATUS_4 = 0x32;
- public static final int MSG_WIFI_5 = 0x33;
- public static final int MSG_AZ735_GPS = 0x32; // only extended
- public static final int MSG_AZ735_ALARM = 0x33; // only extended
+ public static final int MSG_GPS_LBS_EXTEND = 0x1E; // JI09
+ public static final int MSG_HEARTBEAT = 0x23; // GK310
+ public static final int MSG_ADDRESS_REQUEST = 0x2A; // GK310
+ public static final int MSG_ADDRESS_RESPONSE = 0x97; // GK310
+ public static final int MSG_GPS_LBS_5 = 0x31; // AZ735 & SL4X
+ public static final int MSG_GPS_LBS_STATUS_4 = 0x32; // AZ735 & SL4X
+ public static final int MSG_WIFI_5 = 0x33; // AZ735 & SL4X
+ public static final int MSG_LBS_3 = 0x34; // SL4X
+ public static final int MSG_AZ735_GPS = 0x32; // AZ735 (extended)
+ public static final int MSG_AZ735_ALARM = 0x33; // AZ735 (only extended)
public static final int MSG_X1_GPS = 0x34;
public static final int MSG_X1_PHOTO_INFO = 0x35;
public static final int MSG_X1_PHOTO_DATA = 0x36;
@@ -93,33 +93,67 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_COMMAND_0 = 0x80;
public static final int MSG_COMMAND_1 = 0x81;
public static final int MSG_COMMAND_2 = 0x82;
- public static final int MSG_TIME_REQUEST = 0x8A;
+ public static final int MSG_TIME_REQUEST = 0x8A; // GK310
public static final int MSG_INFO = 0x94;
public static final int MSG_SERIAL = 0x9B;
public static final int MSG_STRING_INFO = 0x21;
- public static final int MSG_GPS_2 = 0xA0;
- public static final int MSG_LBS_2 = 0xA1;
- public static final int MSG_WIFI_3 = 0xA2;
- public static final int MSG_FENCE_SINGLE = 0xA3;
- public static final int MSG_FENCE_MULTI = 0xA4;
- public static final int MSG_LBS_ALARM = 0xA5;
- public static final int MSG_LBS_ADDRESS = 0xA7;
- public static final int MSG_OBD = 0x8C;
- public static final int MSG_DTC = 0x65;
- public static final int MSG_PID = 0x66;
- public static final int MSG_BMS = 0x20;
- public static final int MSG_MULTIMEDIA = 0x21;
- public static final int MSG_BMS_2 = 0x40;
- public static final int MSG_MULTIMEDIA_2 = 0x41;
- public static final int MSG_ALARM = 0x95;
+ public static final int MSG_GPS_LBS_7 = 0xA0; // GK310 & JM-VL03
+ public static final int MSG_LBS_2 = 0xA1; // GK310
+ public static final int MSG_WIFI_3 = 0xA2; // GK310
+ public static final int MSG_FENCE_SINGLE = 0xA3; // GK310
+ public static final int MSG_FENCE_MULTI = 0xA4; // GK310 & JM-LL301
+ public static final int MSG_LBS_ALARM = 0xA5; // GK310 & JM-LL301
+ public static final int MSG_LBS_ADDRESS = 0xA7; // GK310
+ public static final int MSG_OBD = 0x8C; // FM08ABC
+ public static final int MSG_DTC = 0x65; // FM08ABC
+ public static final int MSG_PID = 0x66; // FM08ABC
+ public static final int MSG_BMS = 0x40; // WD-209
+ public static final int MSG_MULTIMEDIA = 0x41; // WD-209
+ public static final int MSG_ALARM = 0x95; // JC100
private enum Variant {
VXT01,
+ WANWAY_S20,
+ SR411_MINI,
+ GT06E_CARD,
+ BENWAY,
+ S5,
+ SPACE10X,
STANDARD,
+ OBD6,
+ WETRUST,
+ JC400,
+ SL4X,
}
private Variant variant;
+ private static final Pattern PATTERN_FUEL = new PatternBuilder()
+ .text("!AIOIL,")
+ .number("d+,") // device address
+ .number("d+.d+,") // output value
+ .number("(d+.d+),") // temperature
+ .expression("[^,]+,") // version
+ .number("dd") // back wave
+ .number("d") // software status code
+ .number("d,") // hardware status code
+ .number("(d+.d+),") // measured value
+ .expression("[01],") // movement status
+ .number("d+,") // excited wave times
+ .number("xx") // checksum
+ .compile();
+
+ private static final Pattern PATTERN_LOCATION = new PatternBuilder()
+ .text("Current position!")
+ .number("Lat:([NS])(d+.d+),") // latitude
+ .number("Lon:([EW])(d+.d+),") // longitude
+ .text("Course:").number("(d+.d+),") // course
+ .text("Speed:").number("(d+.d+),") // speed
+ .text("DateTime:")
+ .number("(dddd)-(dd)-(dd) +") // date
+ .number("(dd):(dd):(dd)") // time
+ .compile();
+
private static boolean isSupported(int type) {
return hasGps(type) || hasLbs(type) || hasStatus(type);
}
@@ -139,7 +173,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
case MSG_GPS_LBS_STATUS_4:
case MSG_GPS_PHONE:
case MSG_GPS_LBS_EXTEND:
- case MSG_GPS_2:
+ case MSG_GPS_LBS_7:
case MSG_FENCE_SINGLE:
case MSG_FENCE_MULTI:
return true;
@@ -161,7 +195,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
case MSG_GPS_LBS_STATUS_2:
case MSG_GPS_LBS_STATUS_3:
case MSG_GPS_LBS_STATUS_4:
- case MSG_GPS_2:
+ case MSG_GPS_LBS_7:
case MSG_FENCE_SINGLE:
case MSG_FENCE_MULTI:
case MSG_LBS_ALARM:
@@ -180,6 +214,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
case MSG_GPS_LBS_STATUS_2:
case MSG_GPS_LBS_STATUS_3:
case MSG_GPS_LBS_STATUS_4:
+ case MSG_FENCE_MULTI:
+ case MSG_LBS_ALARM:
return true;
default:
return false;
@@ -236,12 +272,12 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
}
public static boolean decodeGps(Position position, ByteBuf buf, boolean hasLength, TimeZone timezone) {
- return decodeGps(position, buf, hasLength, true, true, timezone);
+ return decodeGps(position, buf, hasLength, true, true, false, timezone);
}
public static boolean decodeGps(
Position position, ByteBuf buf, boolean hasLength, boolean hasSatellites,
- boolean hasSpeed, TimeZone timezone) {
+ boolean hasSpeed, boolean longSpeed, TimeZone timezone) {
DateBuilder dateBuilder = new DateBuilder(timezone)
.setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
@@ -260,7 +296,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
double longitude = buf.readUnsignedInt() / 60.0 / 30000.0;
if (hasSpeed) {
- position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte()));
+ position.setSpeed(UnitsConverter.knotsFromKph(
+ longSpeed ? buf.readUnsignedShort() : buf.readUnsignedByte()));
}
int flags = buf.readUnsignedShort();
@@ -305,9 +342,26 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
}
int mcc = buf.readUnsignedShort();
- int mnc = BitUtil.check(mcc, 15) || type == MSG_GPS_LBS_6 ? buf.readUnsignedShort() : buf.readUnsignedByte();
- int lac = buf.readUnsignedShort();
- long cid = type == MSG_GPS_LBS_6 ? buf.readUnsignedInt() : buf.readUnsignedMedium();
+ int mnc;
+ if (BitUtil.check(mcc, 15) || type == MSG_GPS_LBS_6) {
+ mnc = buf.readUnsignedShort();
+ } else {
+ mnc = buf.readUnsignedByte();
+ }
+ int lac;
+ if (type == MSG_LBS_ALARM || type == MSG_GPS_LBS_7) {
+ lac = buf.readInt();
+ } else {
+ lac = buf.readUnsignedShort();
+ }
+ long cid;
+ if (type == MSG_LBS_ALARM || type == MSG_GPS_LBS_7) {
+ cid = buf.readLong();
+ } else if (type == MSG_GPS_LBS_6) {
+ cid = buf.readUnsignedInt();
+ } else {
+ cid = buf.readUnsignedMedium();
+ }
position.setNetwork(new Network(CellTower.from(BitUtil.to(mcc, 15), mnc, lac, cid)));
@@ -318,7 +372,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
return true;
}
- private boolean decodeStatus(Position position, ByteBuf buf, boolean batteryLevel) {
+ private void decodeStatus(Position position, ByteBuf buf) {
int status = buf.readUnsignedByte();
@@ -353,15 +407,6 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
default:
break;
}
-
- if (batteryLevel) {
- position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte() * 100 / 6);
- } else {
- position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
- }
- position.set(Position.KEY_RSSI, buf.readUnsignedByte());
-
- return true;
}
private String decodeAlarm(short value) {
@@ -381,13 +426,20 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
return Position.ALARM_OVERSPEED;
case 0x0E:
case 0x0F:
+ case 0x19:
return Position.ALARM_LOW_BATTERY;
case 0x11:
return Position.ALARM_POWER_OFF;
+ case 0x0C:
case 0x13:
+ case 0x25:
return Position.ALARM_TAMPERING;
case 0x14:
return Position.ALARM_DOOR;
+ case 0x18:
+ return Position.ALARM_REMOVING;
+ case 0x23:
+ return Position.ALARM_FALL_DOWN;
case 0x29:
return Position.ALARM_ACCELERATION;
case 0x30:
@@ -397,81 +449,27 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
return Position.ALARM_CORNERING;
case 0x2C:
return Position.ALARM_ACCIDENT;
- case 0x23:
- return Position.ALARM_FALL_DOWN;
default:
return null;
}
}
- private static final Pattern PATTERN_FUEL = new PatternBuilder()
- .text("!AIOIL,")
- .number("d+,") // device address
- .number("d+.d+,") // output value
- .number("(d+.d+),") // temperature
- .expression("[^,]+,") // version
- .number("dd") // back wave
- .number("d") // software status code
- .number("d,") // hardware status code
- .number("(d+.d+),") // measured value
- .expression("[01],") // movement status
- .number("d+,") // excited wave times
- .number("xx") // checksum
- .compile();
-
- private Position decodeFuelData(Position position, String sentence) {
- Parser parser = new Parser(PATTERN_FUEL, sentence);
- if (!parser.matches()) {
- return null;
- }
-
- position.set(Position.PREFIX_TEMP + 1, parser.nextDouble(0));
- position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble(0));
-
- return position;
- }
-
- private static final Pattern PATTERN_LOCATION = new PatternBuilder()
- .text("Current position!")
- .number("Lat:([NS])(d+.d+),") // latitude
- .number("Lon:([EW])(d+.d+),") // longitude
- .text("Course:").number("(d+.d+),") // course
- .text("Speed:").number("(d+.d+),") // speed
- .text("DateTime:")
- .number("(dddd)-(dd)-(dd) +") // date
- .number("(dd):(dd):(dd)") // time
- .compile();
-
- private Position decodeLocationString(Position position, String sentence) {
- Parser parser = new Parser(PATTERN_LOCATION, sentence);
- if (!parser.matches()) {
- return null;
- }
-
- position.setValid(true);
- position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG));
- position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG));
- position.setCourse(parser.nextDouble());
- position.setSpeed(parser.nextDouble());
- position.setTime(parser.nextDateTime(Parser.DateTimeFormat.YMD_HMS));
-
- return position;
- }
-
private Object decodeBasic(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
int length = buf.readUnsignedByte();
int dataLength = length - 5;
int type = buf.readUnsignedByte();
+ Position position = new Position(getProtocolName());
DeviceSession deviceSession = null;
if (type != MSG_LOGIN) {
deviceSession = getDeviceSession(channel, remoteAddress);
if (deviceSession == null) {
return null;
}
- if (deviceSession.getTimeZone() == null) {
- deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId()));
+ position.setDeviceId(deviceSession.getDeviceId());
+ if (!deviceSession.contains(DeviceSession.KEY_TIMEZONE)) {
+ deviceSession.set(DeviceSession.KEY_TIMEZONE, getTimeZone(deviceSession.getDeviceId()));
}
}
@@ -481,8 +479,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedShort(); // type
deviceSession = getDeviceSession(channel, remoteAddress, imei);
- if (deviceSession != null && deviceSession.getTimeZone() == null) {
- deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId()));
+ if (deviceSession != null && !deviceSession.contains(DeviceSession.KEY_TIMEZONE)) {
+ deviceSession.set(DeviceSession.KEY_TIMEZONE, getTimeZone(deviceSession.getDeviceId()));
}
if (dataLength > 10) {
@@ -494,23 +492,21 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
offset = -offset;
}
if (deviceSession != null) {
- TimeZone timeZone = deviceSession.getTimeZone();
+ TimeZone timeZone = deviceSession.get(DeviceSession.KEY_TIMEZONE);
if (timeZone.getRawOffset() == 0) {
timeZone.setRawOffset(offset * 1000);
- deviceSession.setTimeZone(timeZone);
+ deviceSession.set(DeviceSession.KEY_TIMEZONE, timeZone);
}
}
-
}
if (deviceSession != null) {
sendResponse(channel, false, type, buf.getShort(buf.writerIndex() - 6), null);
}
- } else if (type == MSG_HEARTBEAT) {
+ return null;
- Position position = new Position(getProtocolName());
- position.setDeviceId(deviceSession.getDeviceId());
+ } else if (type == MSG_HEARTBEAT) {
getLastLocation(position, null);
@@ -539,6 +535,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
content.writeBytes(response.getBytes(StandardCharsets.US_ASCII));
sendResponse(channel, true, MSG_ADDRESS_RESPONSE, 0, content);
+ return null;
+
} else if (type == MSG_TIME_REQUEST) {
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
@@ -551,44 +549,13 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
content.writeByte(calendar.get(Calendar.SECOND));
sendResponse(channel, false, MSG_TIME_REQUEST, 0, content);
- } else if (type == MSG_X1_GPS || type == MSG_X1_PHOTO_INFO) {
-
- return decodeX1(channel, buf, deviceSession, type);
-
- } else if (type == MSG_WIFI || type == MSG_WIFI_2 || type == MSG_WIFI_4) {
-
- return decodeWifi(channel, buf, deviceSession, type);
-
- } else if (type == MSG_INFO) {
-
- Position position = new Position(getProtocolName());
- position.setDeviceId(deviceSession.getDeviceId());
-
- getLastLocation(position, null);
-
- position.set(Position.KEY_POWER, buf.readShort() * 0.01);
-
- return position;
-
- } else {
-
- return decodeBasicOther(channel, buf, deviceSession, type, dataLength);
-
- }
-
- return null;
- }
-
- private Object decodeX1(Channel channel, ByteBuf buf, DeviceSession deviceSession, int type) {
-
- if (type == MSG_X1_GPS) {
+ return null;
- Position position = new Position(getProtocolName());
- position.setDeviceId(deviceSession.getDeviceId());
+ } else if (type == MSG_X1_GPS && variant != Variant.SL4X) {
buf.readUnsignedInt(); // data and alarm
- decodeGps(position, buf, false, deviceSession.getTimeZone());
+ decodeGps(position, buf, false, deviceSession.get(DeviceSession.KEY_TIMEZONE));
buf.readUnsignedShort(); // terminal info
@@ -632,125 +599,135 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
photos.put(pictureId, photo);
sendPhotoRequest(channel, pictureId);
- }
-
- return null;
- }
+ return null;
- private Object decodeWifi(Channel channel, ByteBuf buf, DeviceSession deviceSession, int type) {
+ } else if (type == MSG_WIFI || type == MSG_WIFI_2 || type == MSG_WIFI_4) {
- Position position = new Position(getProtocolName());
- position.setDeviceId(deviceSession.getDeviceId());
+ ByteBuf time = buf.readSlice(6);
+ DateBuilder dateBuilder = new DateBuilder()
+ .setYear(BcdUtil.readInteger(time, 2))
+ .setMonth(BcdUtil.readInteger(time, 2))
+ .setDay(BcdUtil.readInteger(time, 2))
+ .setHour(BcdUtil.readInteger(time, 2))
+ .setMinute(BcdUtil.readInteger(time, 2))
+ .setSecond(BcdUtil.readInteger(time, 2));
+ getLastLocation(position, dateBuilder.getDate());
- ByteBuf time = buf.readSlice(6);
- DateBuilder dateBuilder = new DateBuilder()
- .setYear(BcdUtil.readInteger(time, 2))
- .setMonth(BcdUtil.readInteger(time, 2))
- .setDay(BcdUtil.readInteger(time, 2))
- .setHour(BcdUtil.readInteger(time, 2))
- .setMinute(BcdUtil.readInteger(time, 2))
- .setSecond(BcdUtil.readInteger(time, 2));
- getLastLocation(position, dateBuilder.getDate());
-
- Network network = new Network();
-
- int wifiCount;
- if (type == MSG_WIFI_4) {
- wifiCount = buf.readUnsignedByte();
- } else {
- wifiCount = buf.getUnsignedByte(2);
- }
+ Network network = new Network();
- for (int i = 0; i < wifiCount; i++) {
+ int wifiCount;
if (type == MSG_WIFI_4) {
- buf.skipBytes(2);
+ wifiCount = buf.readUnsignedByte();
+ } else {
+ wifiCount = buf.getUnsignedByte(2);
}
- WifiAccessPoint wifiAccessPoint = new WifiAccessPoint();
- wifiAccessPoint.setMacAddress(String.format("%02x:%02x:%02x:%02x:%02x:%02x",
- buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte(),
- buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()));
- if (type != MSG_WIFI_4) {
- wifiAccessPoint.setSignalStrength((int) buf.readUnsignedByte());
+
+ for (int i = 0; i < wifiCount; i++) {
+ if (type == MSG_WIFI_4) {
+ buf.skipBytes(2);
+ }
+ WifiAccessPoint wifiAccessPoint = new WifiAccessPoint();
+ wifiAccessPoint.setMacAddress(String.format("%02x:%02x:%02x:%02x:%02x:%02x",
+ buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte(),
+ buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte()));
+ if (type != MSG_WIFI_4) {
+ wifiAccessPoint.setSignalStrength((int) buf.readUnsignedByte());
+ }
+ network.addWifiAccessPoint(wifiAccessPoint);
}
- network.addWifiAccessPoint(wifiAccessPoint);
- }
- if (type != MSG_WIFI_4) {
+ if (type != MSG_WIFI_4) {
- int cellCount = buf.readUnsignedByte();
- int mcc = buf.readUnsignedShort();
- int mnc = buf.readUnsignedByte();
- for (int i = 0; i < cellCount; i++) {
- network.addCellTower(CellTower.from(
- mcc, mnc, buf.readUnsignedShort(), buf.readUnsignedShort(), buf.readUnsignedByte()));
- }
+ int cellCount = buf.readUnsignedByte();
+ int mcc = buf.readUnsignedShort();
+ int mnc = buf.readUnsignedByte();
+ for (int i = 0; i < cellCount; i++) {
+ network.addCellTower(CellTower.from(
+ mcc, mnc, buf.readUnsignedShort(), buf.readUnsignedShort(), buf.readUnsignedByte()));
+ }
+
+ if (channel != null) {
+ ByteBuf response = Unpooled.buffer();
+ response.writeShort(0x7878);
+ response.writeByte(0);
+ response.writeByte(type);
+ response.writeBytes(time.resetReaderIndex());
+ response.writeByte('\r');
+ response.writeByte('\n');
+ channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress()));
+ }
- if (channel != null) {
- ByteBuf response = Unpooled.buffer();
- response.writeShort(0x7878);
- response.writeByte(0);
- response.writeByte(type);
- response.writeBytes(time.resetReaderIndex());
- response.writeByte('\r');
- response.writeByte('\n');
- channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress()));
}
- }
+ position.setNetwork(network);
- position.setNetwork(network);
+ return position;
- return position;
- }
+ } else if (type == MSG_INFO) {
- private Object decodeBasicOther(
- Channel channel, ByteBuf buf, DeviceSession deviceSession, int type, int dataLength) {
+ getLastLocation(position, null);
- Position position = new Position(getProtocolName());
- position.setDeviceId(deviceSession.getDeviceId());
+ position.set(Position.KEY_POWER, buf.readShort() * 0.01);
+
+ return position;
- if (type == MSG_LBS_STATUS && dataLength >= 18) {
+ } else if (type == MSG_LBS_MULTIPLE_3 && variant == Variant.SR411_MINI) {
- return null; // space10x multi-lbs message
+ decodeGps(position, buf, false, deviceSession.get(DeviceSession.KEY_TIMEZONE));
+
+ decodeLbs(position, buf, type, false);
+
+ position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0);
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01);
+
+ return position;
} else if (type == MSG_LBS_MULTIPLE_1 || type == MSG_LBS_MULTIPLE_2 || type == MSG_LBS_MULTIPLE_3
- || type == MSG_LBS_EXTEND || type == MSG_LBS_WIFI || type == MSG_LBS_2
+ || type == MSG_LBS_EXTEND || type == MSG_LBS_WIFI || type == MSG_LBS_2 || type == MSG_LBS_3
|| type == MSG_WIFI_3 || type == MSG_WIFI_5) {
- boolean longFormat = type == MSG_LBS_2 || type == MSG_WIFI_3 || type == MSG_WIFI_5;
-
- DateBuilder dateBuilder = new DateBuilder(deviceSession.getTimeZone())
+ DateBuilder dateBuilder = new DateBuilder((TimeZone) deviceSession.get(DeviceSession.KEY_TIMEZONE))
.setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
.setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
getLastLocation(position, dateBuilder.getDate());
- boolean hasCellCount = type == MSG_LBS_MULTIPLE_3 && dataLength == 44;
-
- if (hasCellCount) {
+ if (variant == Variant.WANWAY_S20 || variant == Variant.SL4X) {
buf.readUnsignedByte(); // ta
}
int mcc = buf.readUnsignedShort();
- int mnc = BitUtil.check(mcc, 15) ? buf.readUnsignedShort() : buf.readUnsignedByte();
+ int mnc = BitUtil.check(mcc, 15) || variant == Variant.SL4X
+ ? buf.readUnsignedShort() : buf.readUnsignedByte();
Network network = new Network();
- int cellCount = hasCellCount ? buf.readUnsignedByte() : type == MSG_WIFI_5 ? 6 : 7;
+ int cellCount = variant == Variant.WANWAY_S20 ? buf.readUnsignedByte() : type == MSG_WIFI_5 ? 6 : 7;
for (int i = 0; i < cellCount; i++) {
- int lac = longFormat ? buf.readInt() : buf.readUnsignedShort();
- int cid = longFormat ? (int) buf.readLong() : buf.readUnsignedMedium();
+ int lac;
+ int cid;
+ if (type == MSG_LBS_2 || type == MSG_WIFI_3) {
+ lac = buf.readInt();
+ cid = (int) buf.readLong();
+ } else if (type == MSG_WIFI_5 || type == MSG_LBS_3) {
+ lac = buf.readUnsignedShort();
+ cid = (int) buf.readUnsignedInt();
+ } else {
+ lac = buf.readUnsignedShort();
+ cid = buf.readUnsignedMedium();
+ }
int rssi = -buf.readUnsignedByte();
if (lac > 0) {
network.addCellTower(CellTower.from(BitUtil.to(mcc, 15), mnc, lac, cid, rssi));
}
}
- if (!hasCellCount) {
+ if (variant != Variant.WANWAY_S20 && variant != Variant.SL4X) {
buf.readUnsignedByte(); // ta
}
if (type != MSG_LBS_MULTIPLE_1 && type != MSG_LBS_MULTIPLE_2 && type != MSG_LBS_MULTIPLE_3
- && type != MSG_LBS_2) {
+ && type != MSG_LBS_2 && type != MSG_LBS_3) {
int wifiCount = buf.readUnsignedByte();
for (int i = 0; i < wifiCount; i++) {
String mac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:");
@@ -777,7 +754,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
}
}
- } else if (type == MSG_BMS || type == MSG_BMS_2) {
+ } else if (type == MSG_BMS) {
buf.skipBytes(8); // serial number
@@ -809,35 +786,199 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
return position;
+ } else if (type == MSG_STATUS && buf.readableBytes() == 22) {
+
+ getLastLocation(position, null);
+
+ buf.readUnsignedByte(); // information content
+ buf.readUnsignedShort(); // satellites
+ buf.readUnsignedByte(); // alarm
+ buf.readUnsignedByte(); // language
+
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+
+ buf.readUnsignedByte(); // working mode
+ buf.readUnsignedShort(); // working voltage
+ buf.readUnsignedByte(); // reserved
+ buf.readUnsignedShort(); // working times
+ buf.readUnsignedShort(); // working time
+
+ int value = buf.readUnsignedShort();
+ double temperature = BitUtil.to(value, 15) * 0.1;
+ position.set(Position.PREFIX_TEMP + 1, BitUtil.check(value, 15) ? temperature : -temperature);
+
} else if (isSupported(type)) {
- if (type == MSG_STATUS && buf.readableBytes() == 22) {
- decodeHeartbeat(buf, position);
+ if (type == MSG_LBS_STATUS && variant == Variant.SPACE10X) {
+ return null; // multi-lbs message
+ }
+
+ if (hasGps(type)) {
+ decodeGps(position, buf, false, deviceSession.get(DeviceSession.KEY_TIMEZONE));
} else {
- decodeBasicUniversal(buf, deviceSession, type, position);
+ getLastLocation(position, null);
+ }
+
+ if (hasLbs(type) && buf.readableBytes() > 6) {
+ boolean hasLength = hasStatus(type)
+ && type != MSG_LBS_STATUS
+ && type != MSG_LBS_ALARM
+ && (type != MSG_GPS_LBS_STATUS_1 || variant != Variant.VXT01);
+ decodeLbs(position, buf, type, hasLength);
+ }
+
+ if (hasStatus(type)) {
+ decodeStatus(position, buf);
+ if (variant == Variant.OBD6) {
+ int signal = buf.readUnsignedShort();
+ int satellites = BitUtil.between(signal, 10, 15) + BitUtil.between(signal, 5, 10);
+ position.set(Position.KEY_SATELLITES, satellites);
+ position.set(Position.KEY_RSSI, BitUtil.to(signal, 5));
+ position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
+ buf.readUnsignedByte(); // language
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ buf.readUnsignedByte(); // working mode
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() / 100.0);
+ } else {
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte() * 100 / 6);
+ position.set(Position.KEY_RSSI, buf.readUnsignedByte());
+ short alarmExtension = buf.readUnsignedByte();
+ if (variant != Variant.VXT01) {
+ position.set(Position.KEY_ALARM, decodeAlarm(alarmExtension));
+ }
+ }
+ }
+
+ if (type == MSG_GPS_LBS_1) {
+ if (variant == Variant.GT06E_CARD) {
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
+ String data = buf.readCharSequence(buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString();
+ buf.readUnsignedByte(); // alarm
+ buf.readUnsignedByte(); // swiped
+ position.set(Position.KEY_CARD, data.trim());
+ } else if (variant == Variant.BENWAY) {
+ int mask = buf.readUnsignedShort();
+ position.set(Position.KEY_IGNITION, BitUtil.check(mask, 8 + 7));
+ position.set(Position.PREFIX_IN + 2, BitUtil.check(mask, 8 + 6));
+ if (BitUtil.check(mask, 8 + 4)) {
+ int value = BitUtil.to(mask, 8 + 1);
+ if (BitUtil.check(mask, 8 + 1)) {
+ value = -value;
+ }
+ position.set(Position.PREFIX_TEMP + 1, value);
+ } else {
+ int value = BitUtil.to(mask, 8 + 2);
+ if (BitUtil.check(mask, 8 + 5)) {
+ position.set(Position.PREFIX_ADC + 1, value);
+ } else {
+ position.set(Position.PREFIX_ADC + 1, value * 0.1);
+ }
+ }
+ } else if (variant == Variant.VXT01) {
+ decodeStatus(position, buf);
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
+ position.set(Position.KEY_RSSI, buf.readUnsignedByte());
+ buf.readUnsignedByte(); // alarm extension
+ } else if (variant == Variant.S5) {
+ decodeStatus(position, buf);
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
+ position.set(Position.KEY_RSSI, buf.readUnsignedByte());
+ position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
+ position.set("oil", buf.readUnsignedShort());
+ int temperature = buf.readUnsignedByte();
+ if (BitUtil.check(temperature, 7)) {
+ temperature = -BitUtil.to(temperature, 7);
+ }
+ position.set(Position.PREFIX_TEMP + 1, temperature);
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 10);
+ } else if (variant == Variant.WETRUST) {
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
+ position.set(Position.KEY_CARD, buf.readCharSequence(
+ buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString());
+ position.set(Position.KEY_ALARM, buf.readUnsignedByte() > 0 ? Position.ALARM_GENERAL : null);
+ position.set("cardStatus", buf.readUnsignedByte());
+ position.set(Position.KEY_DRIVING_TIME, buf.readUnsignedShort());
+ }
+ }
+
+ if ((type == MSG_GPS_LBS_2 || type == MSG_GPS_LBS_3 || type == MSG_GPS_LBS_4)
+ && buf.readableBytes() >= 3 + 6) {
+ position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0);
+ position.set(Position.KEY_EVENT, buf.readUnsignedByte()); // reason
+ position.set(Position.KEY_ARCHIVE, buf.readUnsignedByte() > 0);
+ }
+
+ if (type == MSG_GPS_LBS_3) {
+ int module = buf.readUnsignedShort();
+ int subLength = buf.readUnsignedByte();
+ switch (module) {
+ case 0x0027:
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
+ break;
+ case 0x002E:
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
+ break;
+ case 0x003B:
+ position.setAccuracy(buf.readUnsignedShort() * 0.01);
+ break;
+ default:
+ buf.skipBytes(subLength);
+ break;
+ }
+ }
+
+ if (buf.readableBytes() == 3 + 6 || buf.readableBytes() == 3 + 4 + 6) {
+ position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0);
+ buf.readUnsignedByte(); // upload mode
+ position.set(Position.KEY_ARCHIVE, buf.readUnsignedByte() > 0 ? true : null);
+ }
+
+ if (buf.readableBytes() == 4 + 6) {
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
}
} else if (type == MSG_ALARM) {
+
boolean extendedAlarm = dataLength > 7;
if (extendedAlarm) {
- decodeGps(position, buf, false, false, false, deviceSession.getTimeZone());
+ if (variant == Variant.JC400) {
+ buf.readUnsignedShort(); // marker
+ buf.readUnsignedByte(); // version
+ }
+ decodeGps(
+ position, buf, false,
+ variant == Variant.JC400, variant == Variant.JC400, variant == Variant.JC400,
+ deviceSession.get(DeviceSession.KEY_TIMEZONE));
} else {
- DateBuilder dateBuilder = new DateBuilder(deviceSession.getTimeZone())
+ DateBuilder dateBuilder = new DateBuilder((TimeZone) deviceSession.get(DeviceSession.KEY_TIMEZONE))
.setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
.setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
getLastLocation(position, dateBuilder.getDate());
}
- short alarmType = buf.readUnsignedByte();
- switch (alarmType) {
+ if (variant == Variant.JC400) {
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1);
+ }
+ short event = buf.readUnsignedByte();
+ position.set(Position.KEY_EVENT, event);
+ switch (event) {
case 0x01:
position.set(Position.KEY_ALARM, extendedAlarm ? Position.ALARM_SOS : Position.ALARM_GENERAL);
break;
+ case 0x0E:
+ position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER);
+ break;
+ case 0x76:
+ position.set(Position.KEY_ALARM, Position.ALARM_TEMPERATURE);
+ break;
case 0x80:
position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION);
break;
case 0x87:
position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED);
break;
+ case 0x88:
+ position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT);
+ break;
case 0x90:
position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
break;
@@ -851,9 +992,9 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT);
break;
default:
- position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
break;
}
+
} else {
if (dataLength > 0) {
@@ -879,117 +1020,6 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
- private void decodeHeartbeat(ByteBuf buf, Position position) {
-
- getLastLocation(position, null);
-
- buf.readUnsignedByte(); // information content
- buf.readUnsignedShort(); // satellites
- buf.readUnsignedByte(); // alarm
- buf.readUnsignedByte(); // language
-
- position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
-
- buf.readUnsignedByte(); // working mode
- buf.readUnsignedShort(); // working voltage
- buf.readUnsignedByte(); // reserved
- buf.readUnsignedShort(); // working times
- buf.readUnsignedShort(); // working time
-
- int value = buf.readUnsignedShort();
- double temperature = BitUtil.to(value, 15) * 0.1;
- position.set(Position.PREFIX_TEMP + 1, BitUtil.check(value, 15) ? temperature : -temperature);
-
- }
-
- private void decodeBasicUniversal(ByteBuf buf, DeviceSession deviceSession, int type, Position position) {
-
- if (hasGps(type)) {
- decodeGps(position, buf, false, deviceSession.getTimeZone());
- } else {
- getLastLocation(position, null);
- }
-
- if (hasLbs(type)) {
- decodeLbs(position, buf, type, hasStatus(type));
- }
-
- if (hasStatus(type)) {
- decodeStatus(position, buf, true);
- position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
- }
-
- if (type == MSG_GPS_LBS_1) {
- if (buf.readableBytes() > 75 + 6) {
- position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
- String data = buf.readCharSequence(buf.readUnsignedByte(), StandardCharsets.US_ASCII).toString();
- buf.readUnsignedByte(); // alarm
- buf.readUnsignedByte(); // swiped
- position.set("driverLicense", data.trim());
- } else if (buf.readableBytes() == 8) {
- int mask = buf.readUnsignedShort();
- position.set(Position.KEY_IGNITION, BitUtil.check(mask, 8 + 7));
- position.set(Position.PREFIX_IN + 2, BitUtil.check(mask, 8 + 6));
- if (BitUtil.check(mask, 8 + 4)) {
- int value = BitUtil.to(mask, 8 + 1);
- if (BitUtil.check(mask, 8 + 1)) {
- value = -value;
- }
- position.set(Position.PREFIX_TEMP + 1, value);
- } else {
- int value = BitUtil.to(mask, 8 + 2);
- if (BitUtil.check(mask, 8 + 5)) {
- position.set(Position.PREFIX_ADC + 1, value);
- } else {
- position.set(Position.PREFIX_ADC + 1, value * 0.1);
- }
- }
- } else if (buf.readableBytes() == 11) {
- decodeStatus(position, buf, false);
- buf.readUnsignedByte(); // alarm extension
- } else if (buf.readableBytes() == 18) {
- decodeStatus(position, buf, false);
- position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
- position.set("oil", buf.readUnsignedShort());
- int temperature = buf.readUnsignedByte();
- if (BitUtil.check(temperature, 7)) {
- temperature = -BitUtil.to(temperature, 7);
- }
- position.set(Position.PREFIX_TEMP + 1, temperature);
- position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 10);
- }
- }
-
- if ((type == MSG_GPS_LBS_2 || type == MSG_GPS_LBS_3 || type == MSG_GPS_LBS_4) && buf.readableBytes() >= 3 + 6) {
- position.set(Position.KEY_IGNITION, buf.readUnsignedByte() > 0);
- position.set(Position.KEY_EVENT, buf.readUnsignedByte()); // reason
- position.set(Position.KEY_ARCHIVE, buf.readUnsignedByte() > 0);
- }
-
- if (type == MSG_GPS_LBS_3) {
- int module = buf.readUnsignedShort();
- int length = buf.readUnsignedByte();
- switch (module) {
- case 0x0027:
- position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
- break;
- case 0x002E:
- position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
- break;
- case 0x003B:
- position.setAccuracy(buf.readUnsignedShort() * 0.01);
- break;
- default:
- buf.skipBytes(length);
- break;
- }
- }
-
- if (buf.readableBytes() == 4 + 6) {
- position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
- }
- }
-
private Object decodeExtended(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
@@ -997,8 +1027,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- if (deviceSession.getTimeZone() == null) {
- deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId()));
+ if (!deviceSession.contains(DeviceSession.KEY_TIMEZONE)) {
+ deviceSession.set(DeviceSession.KEY_TIMEZONE, getTimeZone(deviceSession.getDeviceId()));
}
Position position = new Position(getProtocolName());
@@ -1017,7 +1047,16 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
data = buf.readSlice(buf.readableBytes() - 6).toString(StandardCharsets.UTF_16BE);
}
- if (decodeLocationString(position, data) == null) {
+ Parser parser = new Parser(PATTERN_LOCATION, data);
+
+ if (parser.matches()) {
+ position.setValid(true);
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG));
+ position.setCourse(parser.nextDouble());
+ position.setSpeed(parser.nextDouble());
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.YMD_HMS));
+ } else {
getLastLocation(position, null);
position.set(Position.KEY_RESULT, data);
}
@@ -1031,31 +1070,85 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
getLastLocation(position, null);
if (subType == 0x00) {
+
position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShort() * 0.01);
return position;
+
+ } else if (subType == 0x04) {
+
+ CharSequence content = buf.readCharSequence(buf.readableBytes() - 4 - 2, StandardCharsets.US_ASCII);
+ String[] values = content.toString().split(";");
+ for (String value : values) {
+ String[] pair = value.split("=");
+ switch (pair[0]) {
+ case "ALM1":
+ case "ALM2":
+ case "ALM3":
+ position.set("alarm" + pair[0].charAt(3) + "Status", Integer.parseInt(pair[1], 16));
+ case "STA1":
+ position.set("otherStatus", Integer.parseInt(pair[1], 16));
+ break;
+ case "DYD":
+ position.set("engineStatus", Integer.parseInt(pair[1], 16));
+ break;
+ default:
+ break;
+ }
+ }
+ return position;
+
} else if (subType == 0x05) {
+
+ if (buf.readableBytes() >= 6 + 1 + 6) {
+ DateBuilder dateBuilder = new DateBuilder((TimeZone) deviceSession.get(DeviceSession.KEY_TIMEZONE))
+ .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
+ position.setDeviceTime(dateBuilder.getDate());
+ }
+
int flags = buf.readUnsignedByte();
position.set(Position.KEY_DOOR, BitUtil.check(flags, 0));
position.set(Position.PREFIX_IO + 1, BitUtil.check(flags, 2));
return position;
+
} else if (subType == 0x0a) {
+
buf.skipBytes(8); // imei
buf.skipBytes(8); // imsi
position.set(Position.KEY_ICCID, ByteBufUtil.hexDump(buf.readSlice(10)).replaceAll("f", ""));
return position;
+
} else if (subType == 0x0d) {
+
if (buf.getByte(buf.readerIndex()) != '!') {
buf.skipBytes(6);
}
- return decodeFuelData(position, buf.toString(
+
+ Parser parser = new Parser(PATTERN_FUEL, buf.toString(
buf.readerIndex(), buf.readableBytes() - 4 - 2, StandardCharsets.US_ASCII));
+ if (!parser.matches()) {
+ return null;
+ }
+
+ position.set(Position.PREFIX_TEMP + 1, parser.nextDouble(0));
+ position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble(0));
+
+ return position;
+
} else if (subType == 0x1b) {
- buf.readUnsignedByte(); // header
- buf.readUnsignedByte(); // type
- position.set(Position.KEY_DRIVER_UNIQUE_ID, ByteBufUtil.hexDump(buf.readSlice(4)));
- buf.readUnsignedByte(); // checksum
- buf.readUnsignedByte(); // footer
+
+ if (Character.isLetter(buf.getUnsignedByte(buf.readerIndex()))) {
+ String data = buf.readCharSequence(buf.readableBytes() - 6, StandardCharsets.US_ASCII).toString();
+ position.set("serial", data.trim());
+ } else {
+ buf.readUnsignedByte(); // header
+ buf.readUnsignedByte(); // type
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, ByteBufUtil.hexDump(buf.readSlice(4)));
+ buf.readUnsignedByte(); // checksum
+ buf.readUnsignedByte(); // footer
+ }
return position;
+
}
} else if (type == MSG_X1_PHOTO_DATA) {
@@ -1070,15 +1163,13 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
if (photo.writableBytes() > 0) {
sendPhotoRequest(channel, pictureId);
} else {
- Device device = Context.getDeviceManager().getById(deviceSession.getDeviceId());
- position.set(
- Position.KEY_IMAGE, Context.getMediaManager().writeFile(device.getUniqueId(), photo, "jpg"));
+ position.set(Position.KEY_IMAGE, writeMediaFile(deviceSession.getUniqueId(), photo, "jpg"));
photos.remove(pictureId).release();
}
} else if (type == MSG_AZ735_GPS || type == MSG_AZ735_ALARM) {
- if (!decodeGps(position, buf, true, deviceSession.getTimeZone())) {
+ if (!decodeGps(position, buf, true, deviceSession.get(DeviceSession.KEY_TIMEZONE))) {
getLastLocation(position, position.getDeviceTime());
}
@@ -1123,7 +1214,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
} else if (type == MSG_OBD) {
- DateBuilder dateBuilder = new DateBuilder(deviceSession.getTimeZone())
+ DateBuilder dateBuilder = new DateBuilder((TimeZone) deviceSession.get(DeviceSession.KEY_TIMEZONE))
.setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
.setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
@@ -1170,132 +1261,111 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
} else if (type == MSG_GPS_MODULAR) {
- return decodeExtendedModular(channel, buf, deviceSession);
+ while (buf.readableBytes() > 6) {
+ int moduleType = buf.readUnsignedShort();
+ int moduleLength = buf.readUnsignedShort();
- } else {
-
- return decodeExtendedOther(channel, buf, deviceSession, type);
-
- }
-
- return null;
- }
-
- private Object decodeExtendedModular(Channel channel, ByteBuf buf, DeviceSession deviceSession) {
-
- Position position = new Position(getProtocolName());
- position.setDeviceId(deviceSession.getDeviceId());
-
- while (buf.readableBytes() > 6) {
- int moduleType = buf.readUnsignedShort();
- int moduleLength = buf.readUnsignedShort();
-
- switch (moduleType) {
- case 0x03:
- position.set(Position.KEY_ICCID, ByteBufUtil.hexDump(buf.readSlice(10)));
- break;
- case 0x09:
- position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
- break;
- case 0x0a:
- position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedByte());
- break;
- case 0x11:
- CellTower cellTower = CellTower.from(
- buf.readUnsignedShort(),
- buf.readUnsignedShort(),
- buf.readUnsignedShort(),
- buf.readUnsignedMedium(),
- buf.readUnsignedByte());
- if (cellTower.getCellId() > 0) {
- position.setNetwork(new Network(cellTower));
- }
- break;
- case 0x18:
- position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01);
- break;
- case 0x28:
- position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1);
- break;
- case 0x29:
- position.set(Position.KEY_INDEX, buf.readUnsignedInt());
- break;
- case 0x2a:
- int input = buf.readUnsignedByte();
- position.set(Position.KEY_DOOR, BitUtil.to(input, 4) > 0);
- position.set("tamper", BitUtil.from(input, 4) > 0);
- break;
- case 0x2b:
- int event = buf.readUnsignedByte();
- switch (event) {
- case 0x11:
- position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY);
- break;
- case 0x12:
- position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER);
- break;
- case 0x13:
- position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT);
- break;
- case 0x14:
- position.set(Position.KEY_ALARM, Position.ALARM_REMOVING);
- break;
- default:
- break;
- }
- position.set(Position.KEY_EVENT, event);
- break;
- case 0x2e:
- position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE());
- break;
- case 0x33:
- position.setTime(new Date(buf.readUnsignedInt() * 1000));
- position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
- position.setAltitude(buf.readShort());
-
- double latitude = buf.readUnsignedInt() / 60.0 / 30000.0;
- double longitude = buf.readUnsignedInt() / 60.0 / 30000.0;
- position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte()));
-
- int flags = buf.readUnsignedShort();
- position.setCourse(BitUtil.to(flags, 10));
- position.setValid(BitUtil.check(flags, 12));
-
- if (!BitUtil.check(flags, 10)) {
- latitude = -latitude;
- }
- if (BitUtil.check(flags, 11)) {
- longitude = -longitude;
- }
-
- position.setLatitude(latitude);
- position.setLongitude(longitude);
- break;
- case 0x34:
- position.set(Position.KEY_EVENT, buf.readUnsignedByte());
- buf.readUnsignedIntLE(); // time
- buf.skipBytes(buf.readUnsignedByte()); // content
- break;
- default:
- buf.skipBytes(moduleLength);
- break;
+ switch (moduleType) {
+ case 0x03:
+ position.set(Position.KEY_ICCID, ByteBufUtil.hexDump(buf.readSlice(10)));
+ break;
+ case 0x09:
+ position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
+ break;
+ case 0x0a:
+ position.set(Position.KEY_SATELLITES_VISIBLE, buf.readUnsignedByte());
+ break;
+ case 0x11:
+ CellTower cellTower = CellTower.from(
+ buf.readUnsignedShort(),
+ buf.readUnsignedShort(),
+ buf.readUnsignedShort(),
+ buf.readUnsignedMedium(),
+ buf.readUnsignedByte());
+ if (cellTower.getCellId() > 0) {
+ position.setNetwork(new Network(cellTower));
+ }
+ break;
+ case 0x18:
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01);
+ break;
+ case 0x28:
+ position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1);
+ break;
+ case 0x29:
+ position.set(Position.KEY_INDEX, buf.readUnsignedInt());
+ break;
+ case 0x2a:
+ int input = buf.readUnsignedByte();
+ position.set(Position.KEY_DOOR, BitUtil.to(input, 4) > 0);
+ position.set("tamper", BitUtil.from(input, 4) > 0);
+ break;
+ case 0x2b:
+ int event = buf.readUnsignedByte();
+ switch (event) {
+ case 0x11:
+ position.set(Position.KEY_ALARM, Position.ALARM_LOW_BATTERY);
+ break;
+ case 0x12:
+ position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER);
+ break;
+ case 0x13:
+ position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT);
+ break;
+ case 0x14:
+ position.set(Position.KEY_ALARM, Position.ALARM_REMOVING);
+ break;
+ default:
+ break;
+ }
+ position.set(Position.KEY_EVENT, event);
+ break;
+ case 0x2e:
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE());
+ break;
+ case 0x33:
+ position.setTime(new Date(buf.readUnsignedInt() * 1000));
+ position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
+ position.setAltitude(buf.readShort());
+
+ double latitude = buf.readUnsignedInt() / 60.0 / 30000.0;
+ double longitude = buf.readUnsignedInt() / 60.0 / 30000.0;
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte()));
+
+ int flags = buf.readUnsignedShort();
+ position.setCourse(BitUtil.to(flags, 10));
+ position.setValid(BitUtil.check(flags, 12));
+
+ if (!BitUtil.check(flags, 10)) {
+ latitude = -latitude;
+ }
+ if (BitUtil.check(flags, 11)) {
+ longitude = -longitude;
+ }
+
+ position.setLatitude(latitude);
+ position.setLongitude(longitude);
+ break;
+ case 0x34:
+ position.set(Position.KEY_EVENT, buf.readUnsignedByte());
+ buf.readUnsignedIntLE(); // time
+ buf.skipBytes(buf.readUnsignedByte()); // content
+ break;
+ default:
+ buf.skipBytes(moduleLength);
+ break;
+ }
}
- }
-
- if (position.getFixTime() == null) {
- getLastLocation(position, null);
- }
-
- sendResponse(channel, false, MSG_GPS_MODULAR, buf.readUnsignedShort(), null);
- return position;
- }
+ if (position.getFixTime() == null) {
+ getLastLocation(position, null);
+ }
- private Object decodeExtendedOther(Channel channel, ByteBuf buf, DeviceSession deviceSession, int type) {
+ sendResponse(channel, false, MSG_GPS_MODULAR, buf.readUnsignedShort(), null);
- Position position = null;
+ return position;
- if (type == MSG_MULTIMEDIA || type == MSG_MULTIMEDIA_2) {
+ } else if (type == MSG_MULTIMEDIA) {
buf.skipBytes(8); // serial number
long timestamp = buf.readUnsignedInt() * 1000;
@@ -1328,9 +1398,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
getLastLocation(position, new Date(timestamp));
- Device device = Context.getDeviceManager().getById(deviceSession.getDeviceId());
- position.set(Position.KEY_IMAGE,
- Context.getMediaManager().writeFile(device.getUniqueId(), photo, "jpg"));
+ position.set(Position.KEY_IMAGE, writeMediaFile(deviceSession.getUniqueId(), photo, "jpg"));
photos.remove(mediaId).release();
}
}
@@ -1348,19 +1416,13 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
getLastLocation(position, null);
buf.readUnsignedByte(); // external device type code
- int length = buf.readableBytes() - 9; // line break + checksum + index + checksum + footer
- if (length <= 0) {
- return null;
- } else if (length < 8) {
- position.set(
- Position.PREFIX_TEMP + 1,
- Double.parseDouble(buf.readCharSequence(length - 1, StandardCharsets.US_ASCII).toString()));
+ ByteBuf data = buf.readSlice(buf.readableBytes() - 6); // index + checksum + footer
+ if (BufferUtil.isPrintable(data, data.readableBytes())) {
+ String value = data.readCharSequence(data.readableBytes(), StandardCharsets.US_ASCII).toString();
+ position.set(Position.KEY_RESULT, value.trim());
} else {
- buf.readUnsignedByte(); // card type
- position.set(
- Position.KEY_DRIVER_UNIQUE_ID,
- buf.readCharSequence(length - 1, StandardCharsets.US_ASCII).toString());
+ position.set(Position.KEY_RESULT, ByteBufUtil.hexDump(data));
}
return position;
@@ -1386,6 +1448,26 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
variant = Variant.VXT01;
} else if (header == 0x7878 && type == MSG_GPS_LBS_STATUS_1 && length == 0x24) {
variant = Variant.VXT01;
+ } else if (header == 0x7878 && type == MSG_LBS_MULTIPLE_3 && length == 0x31) {
+ variant = Variant.WANWAY_S20;
+ } else if (header == 0x7878 && type == MSG_LBS_MULTIPLE_3 && length == 0x2e) {
+ variant = Variant.SR411_MINI;
+ } else if (header == 0x7878 && type == MSG_GPS_LBS_1 && length >= 0x71) {
+ variant = Variant.GT06E_CARD;
+ } else if (header == 0x7878 && type == MSG_GPS_LBS_1 && length == 0x21) {
+ variant = Variant.BENWAY;
+ } else if (header == 0x7878 && type == MSG_GPS_LBS_1 && length == 0x2b) {
+ variant = Variant.S5;
+ } else if (header == 0x7878 && type == MSG_LBS_STATUS && length >= 0x17) {
+ variant = Variant.SPACE10X;
+ } else if (header == 0x7878 && type == MSG_STATUS && length == 0x13) {
+ variant = Variant.OBD6;
+ } else if (header == 0x7878 && type == MSG_GPS_LBS_1 && length == 0x29) {
+ variant = Variant.WETRUST;
+ } else if (header == 0x7878 && type == MSG_ALARM && buf.getUnsignedShort(buf.readerIndex() + 4) == 0xffff) {
+ variant = Variant.JC400;
+ } else if (header == 0x7878 && type == MSG_LBS_3 && length == 0x37) {
+ variant = Variant.SL4X;
} else {
variant = Variant.STANDARD;
}
diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java
index 9115ba10f..dc5dd446f 100644
--- a/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -18,10 +18,12 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.traccar.BaseProtocolEncoder;
-import org.traccar.Context;
+import org.traccar.Protocol;
+import org.traccar.config.Keys;
import org.traccar.helper.Checksum;
+import org.traccar.helper.model.AttributeUtil;
import org.traccar.model.Command;
-import org.traccar.Protocol;
+import org.traccar.model.Device;
import java.nio.charset.StandardCharsets;
@@ -33,8 +35,8 @@ public class Gt06ProtocolEncoder extends BaseProtocolEncoder {
private ByteBuf encodeContent(long deviceId, String content) {
- boolean language = Context.getIdentityManager()
- .lookupAttributeBoolean(deviceId, getProtocolName() + ".language", false, false, true);
+ boolean language = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_LANGUAGE.withPrefix(getProtocolName()), deviceId);
ByteBuf buf = Unpooled.buffer();
@@ -43,7 +45,7 @@ public class Gt06ProtocolEncoder extends BaseProtocolEncoder {
buf.writeByte(1 + 1 + 4 + content.length() + 2 + 2 + (language ? 2 : 0)); // message length
- buf.writeByte(0x80); // message type
+ buf.writeByte(Gt06ProtocolDecoder.MSG_COMMAND_0);
buf.writeByte(4 + content.length()); // command length
buf.writeInt(0);
@@ -66,19 +68,31 @@ public class Gt06ProtocolEncoder extends BaseProtocolEncoder {
@Override
protected Object encodeCommand(Command command) {
- boolean alternative = Context.getIdentityManager().lookupAttributeBoolean(
- command.getDeviceId(), getProtocolName() + ".alternative", false, false, true);
+ boolean alternative = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_ALTERNATIVE.withPrefix(getProtocolName()), command.getDeviceId());
+
+ String password = AttributeUtil.getDevicePassword(
+ getCacheManager(), command.getDeviceId(), getProtocolName(), "123456");
- String password = Context.getIdentityManager()
- .getDevicePassword(command.getDeviceId(), getProtocolName(), "123456");
+ Device device = getCacheManager().getObject(Device.class, command.getDeviceId());
switch (command.getType()) {
case Command.TYPE_ENGINE_STOP:
- return encodeContent(command.getDeviceId(),
- alternative ? "DYD," + password + "#" : "Relay,1#");
+ if ("G109".equals(device.getModel())) {
+ return encodeContent(command.getDeviceId(), "DYD#");
+ } else if (alternative) {
+ return encodeContent(command.getDeviceId(), "DYD," + password + "#");
+ } else {
+ return encodeContent(command.getDeviceId(), "Relay,1#");
+ }
case Command.TYPE_ENGINE_RESUME:
- return encodeContent(command.getDeviceId(),
- alternative ? "HFYD," + password + "#" : "Relay,0#");
+ if ("G109".equals(device.getModel())) {
+ return encodeContent(command.getDeviceId(), "HFYD#");
+ } else if (alternative) {
+ return encodeContent(command.getDeviceId(), "HFYD," + password + "#");
+ } else {
+ return encodeContent(command.getDeviceId(), "Relay,0#");
+ }
case Command.TYPE_CUSTOM:
return encodeContent(command.getDeviceId(), command.getString(Command.KEY_DATA));
default:
diff --git a/src/main/java/org/traccar/protocol/Gt30Protocol.java b/src/main/java/org/traccar/protocol/Gt30Protocol.java
index aa4ad20b1..fdfc80502 100644
--- a/src/main/java/org/traccar/protocol/Gt30Protocol.java
+++ b/src/main/java/org/traccar/protocol/Gt30Protocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Gt30Protocol extends BaseProtocol {
- public Gt30Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Gt30Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/Gt30ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt30ProtocolDecoder.java
index abf208a46..fb3a2b8ae 100644
--- a/src/main/java/org/traccar/protocol/Gt30ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gt30ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/H02Protocol.java b/src/main/java/org/traccar/protocol/H02Protocol.java
index a5246abc6..ba5aeaa26 100644
--- a/src/main/java/org/traccar/protocol/H02Protocol.java
+++ b/src/main/java/org/traccar/protocol/H02Protocol.java
@@ -17,15 +17,18 @@ package org.traccar.protocol;
import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
-import org.traccar.Context;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class H02Protocol extends BaseProtocol {
- public H02Protocol() {
+ @Inject
+ public H02Protocol(Config config) {
setSupportedDataCommands(
Command.TYPE_ALARM_ARM,
Command.TYPE_ALARM_DISARM,
@@ -33,19 +36,19 @@ public class H02Protocol extends BaseProtocol {
Command.TYPE_ENGINE_RESUME,
Command.TYPE_POSITION_PERIODIC
);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
- int messageLength = Context.getConfig().getInteger(Keys.PROTOCOL_MESSAGE_LENGTH.withPrefix(getName()));
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ int messageLength = config.getInteger(Keys.PROTOCOL_MESSAGE_LENGTH.withPrefix(getName()));
pipeline.addLast(new H02FrameDecoder(messageLength));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new H02ProtocolEncoder(H02Protocol.this));
pipeline.addLast(new H02ProtocolDecoder(H02Protocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new H02ProtocolEncoder(H02Protocol.this));
pipeline.addLast(new H02ProtocolDecoder(H02Protocol.this));
diff --git a/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java b/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java
index 10a272bff..2ad4f644b 100644
--- a/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java
@@ -19,8 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.config.Keys;
@@ -334,7 +333,7 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder {
if (parser.hasNext() && parser.next().equals("V1")) {
sendResponse(channel, remoteAddress, id, "V1");
- } else if (Context.getConfig().getBoolean(Keys.PROTOCOL_ACK.withPrefix(getProtocolName()))) {
+ } else if (getConfig().getBoolean(Keys.PROTOCOL_ACK.withPrefix(getProtocolName()))) {
sendResponse(channel, remoteAddress, id, "R12");
}
@@ -392,7 +391,8 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder {
position.setAltitude(parser.nextInt(0));
- position.setNetwork(new Network(CellTower.fromLacCid(parser.nextHexInt(0), parser.nextHexInt(0))));
+ position.setNetwork(new Network(CellTower.fromLacCid(
+ getConfig(), parser.nextHexInt(0), parser.nextHexInt(0))));
}
if (parser.hasNext()) {
diff --git a/src/main/java/org/traccar/protocol/H02ProtocolEncoder.java b/src/main/java/org/traccar/protocol/H02ProtocolEncoder.java
index 8f1a8c042..86b8c80d4 100644
--- a/src/main/java/org/traccar/protocol/H02ProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/H02ProtocolEncoder.java
@@ -16,10 +16,11 @@
*/
package org.traccar.protocol;
-import org.traccar.Context;
+import org.traccar.Protocol;
import org.traccar.StringProtocolEncoder;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.AttributeUtil;
import org.traccar.model.Command;
-import org.traccar.Protocol;
import java.util.Date;
@@ -59,8 +60,9 @@ public class H02ProtocolEncoder extends StringProtocolEncoder {
return formatCommand(time, uniqueId, "S20", "1", "0");
case Command.TYPE_POSITION_PERIODIC:
String frequency = command.getAttributes().get(Command.KEY_FREQUENCY).toString();
- if (Context.getIdentityManager().lookupAttributeBoolean(
- command.getDeviceId(), getProtocolName() + ".alternative", false, false, true)) {
+ if (AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_ALTERNATIVE.withPrefix(getProtocolName()),
+ command.getDeviceId())) {
return formatCommand(time, uniqueId, "D1", frequency);
} else {
return formatCommand(time, uniqueId, "S71", "22", frequency);
diff --git a/src/main/java/org/traccar/protocol/HaicomProtocol.java b/src/main/java/org/traccar/protocol/HaicomProtocol.java
index 6e5760bd4..bcc491ada 100644
--- a/src/main/java/org/traccar/protocol/HaicomProtocol.java
+++ b/src/main/java/org/traccar/protocol/HaicomProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class HaicomProtocol extends BaseProtocol {
- public HaicomProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public HaicomProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '*'));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/HaicomProtocolDecoder.java b/src/main/java/org/traccar/protocol/HaicomProtocolDecoder.java
index dd20f2aeb..9903e7735 100644
--- a/src/main/java/org/traccar/protocol/HaicomProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/HaicomProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/HomtecsProtocol.java b/src/main/java/org/traccar/protocol/HomtecsProtocol.java
index 34dbf0f51..c04efb945 100644
--- a/src/main/java/org/traccar/protocol/HomtecsProtocol.java
+++ b/src/main/java/org/traccar/protocol/HomtecsProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class HomtecsProtocol extends BaseProtocol {
- public HomtecsProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public HomtecsProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new HomtecsProtocolDecoder(HomtecsProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/HomtecsProtocolDecoder.java b/src/main/java/org/traccar/protocol/HomtecsProtocolDecoder.java
index a93572b5c..5541cb065 100644
--- a/src/main/java/org/traccar/protocol/HomtecsProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/HomtecsProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/HoopoProtocol.java b/src/main/java/org/traccar/protocol/HoopoProtocol.java
index 387b967d3..3fc0887d8 100644
--- a/src/main/java/org/traccar/protocol/HoopoProtocol.java
+++ b/src/main/java/org/traccar/protocol/HoopoProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class HoopoProtocol extends BaseProtocol {
- public HoopoProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public HoopoProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new JsonFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/HoopoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HoopoProtocolDecoder.java
index af51a99c6..7433e7fce 100644
--- a/src/main/java/org/traccar/protocol/HoopoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/HoopoProtocolDecoder.java
@@ -17,12 +17,12 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.model.Position;
-import javax.json.Json;
-import javax.json.JsonObject;
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
import java.io.StringReader;
import java.net.SocketAddress;
import java.time.OffsetDateTime;
diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocol.java b/src/main/java/org/traccar/protocol/HuaShengProtocol.java
index 103f2d501..7246e97e6 100644
--- a/src/main/java/org/traccar/protocol/HuaShengProtocol.java
+++ b/src/main/java/org/traccar/protocol/HuaShengProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,14 +18,26 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+import org.traccar.model.Command;
+
+import jakarta.inject.Inject;
public class HuaShengProtocol extends BaseProtocol {
- public HuaShengProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public HuaShengProtocol(Config config) {
+ setSupportedDataCommands(
+ Command.TYPE_POSITION_PERIODIC,
+ Command.TYPE_OUTPUT_CONTROL,
+ Command.TYPE_ALARM_ARM,
+ Command.TYPE_ALARM_DISARM,
+ Command.TYPE_SET_SPEED_LIMIT);
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HuaShengFrameDecoder());
+ pipeline.addLast(new HuaShengProtocolEncoder(HuaShengProtocol.this));
pipeline.addLast(new HuaShengProtocolDecoder(HuaShengProtocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java
index 891046213..7d634b0f2 100644
--- a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -48,6 +48,10 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_UPFAULT_RSP = 0xFF13;
public static final int MSG_HSO_REQ = 0x0002;
public static final int MSG_HSO_RSP = 0x0003;
+ public static final int MSG_SET_REQ = 0xAA04;
+ public static final int MSG_SET_RSP = 0xFF05;
+ public static final int MSG_CTRL_REQ = 0xAA16;
+ public static final int MSG_CTRL_RSP = 0xFF17;
private void sendResponse(Channel channel, int type, int index, ByteBuf content) {
if (channel != null) {
@@ -225,13 +229,14 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder {
position.setCourse(buf.readUnsignedShort());
position.setAltitude(buf.readUnsignedShort());
- position.set(Position.KEY_ODOMETER, buf.readUnsignedShort() * 1000);
+ buf.readUnsignedShort(); // odometer speed
Network network = new Network();
while (buf.readableBytes() > 4) {
int subtype = buf.readUnsignedShort();
int length = buf.readUnsignedShort() - 4;
+ int endIndex = buf.readerIndex() + length;
switch (subtype) {
case 0x0001:
int coolantTemperature = buf.readUnsignedByte() - 40;
@@ -249,6 +254,9 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte() * 0.4);
buf.readUnsignedInt(); // trip id
+ if (buf.readerIndex() < endIndex) {
+ position.set("adBlueLevel", buf.readUnsignedByte() * 0.4);
+ }
break;
case 0x0005:
position.set(Position.KEY_RSSI, buf.readUnsignedByte());
@@ -256,8 +264,11 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedInt(); // run time
break;
case 0x0009:
- position.set(
- Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString());
+ position.set(Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString());
+ break;
+ case 0x0010:
+ position.set(Position.KEY_ODOMETER, Double.parseDouble(
+ buf.readCharSequence(length, StandardCharsets.US_ASCII).toString()) * 1000);
break;
case 0x0011:
position.set(Position.KEY_HOURS, buf.readUnsignedInt() * 0.05);
@@ -276,7 +287,7 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder {
String[] values = cell.split("@");
network.addCellTower(CellTower.from(
Integer.parseInt(values[0]), Integer.parseInt(values[1]),
- Integer.parseInt(values[2], 16), Integer.parseInt(values[3], 16)));
+ Integer.parseInt(values[2], 16), Long.parseLong(values[3], 16)));
}
break;
case 0x0021:
@@ -291,6 +302,7 @@ public class HuaShengProtocolDecoder extends BaseProtocolDecoder {
buf.skipBytes(length);
break;
}
+ buf.readerIndex(endIndex);
}
if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) {
diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java b/src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java
new file mode 100644
index 000000000..dc34f7b4e
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/HuaShengProtocolEncoder.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import org.traccar.BaseProtocolEncoder;
+import org.traccar.Protocol;
+import org.traccar.model.Command;
+
+public class HuaShengProtocolEncoder extends BaseProtocolEncoder {
+
+ public HuaShengProtocolEncoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private ByteBuf encodeContent(int type, ByteBuf content) {
+
+ ByteBuf buf = Unpooled.buffer();
+ buf.writeByte(0xC0);
+ buf.writeShort(0x0000); // flag and version
+ buf.writeShort(12 + content.readableBytes());
+ buf.writeShort(type);
+ buf.writeShort(0); // checksum
+ buf.writeInt(1); // index
+ buf.writeBytes(content);
+ content.release();
+ buf.writeByte(0xC0);
+
+ return buf;
+ }
+
+ @Override
+ protected Object encodeCommand(Command command) {
+
+ ByteBuf content = Unpooled.buffer(0);
+ switch (command.getType()) {
+ case Command.TYPE_POSITION_PERIODIC:
+ content.writeShort(0x0002);
+ content.writeShort(6); // length
+ content.writeShort(command.getInteger(Command.KEY_FREQUENCY));
+ return encodeContent(HuaShengProtocolDecoder.MSG_SET_REQ, content);
+ case Command.TYPE_OUTPUT_CONTROL:
+ /*
+0x01: Lock the relay1; //relay on
+0x02: Unlock the relay1; //relay off
+0x03: Lock the relay2; //relay2 on
+0x04: Unlock the relay2; //relay2 off
+0x05: Lock the relay3; //relay3 on
+0x06: Unlock the relay3; //realy3 off
+ */
+ content.writeByte(
+ (command.getInteger(Command.KEY_INDEX) - 1) * 2
+ + (2 - command.getInteger(Command.KEY_DATA)));
+ return encodeContent(HuaShengProtocolDecoder.MSG_CTRL_REQ, content);
+ case Command.TYPE_ALARM_ARM:
+ case Command.TYPE_ALARM_DISARM:
+ content.writeShort(0x0001);
+ content.writeShort(5); // length
+ content.writeByte(command.getType().equals(Command.TYPE_ALARM_ARM) ? 1 : 0);
+ return encodeContent(HuaShengProtocolDecoder.MSG_SET_REQ, content);
+ case Command.TYPE_SET_SPEED_LIMIT:
+ content.writeShort(0x0004);
+ content.writeShort(6); // length
+ content.writeShort(command.getInteger(Command.KEY_DATA));
+ return encodeContent(HuaShengProtocolDecoder.MSG_SET_REQ, content);
+ default:
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocol.java b/src/main/java/org/traccar/protocol/HuabaoProtocol.java
index 791672b85..fc12d7d71 100644
--- a/src/main/java/org/traccar/protocol/HuabaoProtocol.java
+++ b/src/main/java/org/traccar/protocol/HuabaoProtocol.java
@@ -18,17 +18,21 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class HuabaoProtocol extends BaseProtocol {
- public HuabaoProtocol() {
+ @Inject
+ public HuabaoProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HuabaoFrameDecoder());
pipeline.addLast(new HuabaoProtocolEncoder(HuabaoProtocol.this));
pipeline.addLast(new HuabaoProtocolDecoder(HuabaoProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
index 0ae08af37..beb1ec41a 100644
--- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BcdUtil;
@@ -51,11 +51,13 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_GENERAL_RESPONSE = 0x8001;
public static final int MSG_GENERAL_RESPONSE_2 = 0x4401;
public static final int MSG_HEARTBEAT = 0x0002;
+ public static final int MSG_HEARTBEAT_2 = 0x0506;
public static final int MSG_TERMINAL_REGISTER = 0x0100;
public static final int MSG_TERMINAL_REGISTER_RESPONSE = 0x8100;
public static final int MSG_TERMINAL_CONTROL = 0x8105;
public static final int MSG_TERMINAL_AUTH = 0x0102;
public static final int MSG_LOCATION_REPORT = 0x0200;
+ public static final int MSG_LOCATION_BATCH_2 = 0x0210;
public static final int MSG_ACCELERATION = 0x2070;
public static final int MSG_LOCATION_REPORT_2 = 0x5501;
public static final int MSG_LOCATION_REPORT_BLIND = 0x5502;
@@ -64,6 +66,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_TIME_SYNC_REQUEST = 0x0109;
public static final int MSG_TIME_SYNC_RESPONSE = 0x8109;
public static final int MSG_PHOTO = 0x8888;
+ public static final int MSG_TRANSPARENT = 0x0900;
public static final int RESULT_SUCCESS = 0;
@@ -122,6 +125,9 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
|| BitUtil.check(value, 10) || BitUtil.check(value, 11)) {
return Position.ALARM_FAULT;
}
+ if (BitUtil.check(value, 7) || BitUtil.check(value, 18)) {
+ return Position.ALARM_LOW_BATTERY;
+ }
if (BitUtil.check(value, 8)) {
return Position.ALARM_POWER_OFF;
}
@@ -145,6 +151,28 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
return BitUtil.check(value, 15) ? -BitUtil.to(value, 15) : BitUtil.to(value, 15);
}
+ private Date readDate(ByteBuf buf, TimeZone timeZone) {
+ DateBuilder dateBuilder = new DateBuilder(timeZone)
+ .setYear(BcdUtil.readInteger(buf, 2))
+ .setMonth(BcdUtil.readInteger(buf, 2))
+ .setDay(BcdUtil.readInteger(buf, 2))
+ .setHour(BcdUtil.readInteger(buf, 2))
+ .setMinute(BcdUtil.readInteger(buf, 2))
+ .setSecond(BcdUtil.readInteger(buf, 2));
+ return dateBuilder.getDate();
+ }
+
+ private String decodeId(ByteBuf id) {
+ String serial = ByteBufUtil.hexDump(id);
+ if (serial.matches("[0-9]+")) {
+ return serial;
+ } else {
+ long imei = id.getUnsignedShort(0);
+ imei = (imei << 32) + id.getUnsignedInt(2);
+ return String.valueOf(imei) + Checksum.luhn(imei);
+ }
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -178,13 +206,13 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
index = buf.readUnsignedShort();
}
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, ByteBufUtil.hexDump(id));
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, decodeId(id));
if (deviceSession == null) {
return null;
}
- if (deviceSession.getTimeZone() == null) {
- deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId(), "GMT+8"));
+ if (!deviceSession.contains(DeviceSession.KEY_TIMEZONE)) {
+ deviceSession.set(DeviceSession.KEY_TIMEZONE, getTimeZone(deviceSession.getDeviceId(), "GMT+8"));
}
if (type == MSG_TERMINAL_REGISTER) {
@@ -193,12 +221,12 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
ByteBuf response = Unpooled.buffer();
response.writeShort(index);
response.writeByte(RESULT_SUCCESS);
- response.writeBytes(ByteBufUtil.hexDump(id).getBytes(StandardCharsets.US_ASCII));
+ response.writeBytes(decodeId(id).getBytes(StandardCharsets.US_ASCII));
channel.writeAndFlush(new NetworkMessage(
formatMessage(MSG_TERMINAL_REGISTER_RESPONSE, id, false, response), remoteAddress));
}
- } else if (type == MSG_TERMINAL_AUTH || type == MSG_HEARTBEAT || type == MSG_PHOTO) {
+ } else if (type == MSG_TERMINAL_AUTH || type == MSG_HEARTBEAT || type == MSG_HEARTBEAT_2 || type == MSG_PHOTO) {
sendGeneralResponse(channel, remoteAddress, id, type, index);
@@ -216,11 +244,11 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
return decodeLocation2(deviceSession, buf, type);
- } else if (type == MSG_LOCATION_BATCH) {
+ } else if (type == MSG_LOCATION_BATCH || type == MSG_LOCATION_BATCH_2) {
sendGeneralResponse(channel, remoteAddress, id, type, index);
- return decodeLocationBatch(deviceSession, buf);
+ return decodeLocationBatch(deviceSession, buf, type);
} else if (type == MSG_TIME_SYNC_REQUEST) {
@@ -264,6 +292,12 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
return position;
+ } else if (type == MSG_TRANSPARENT) {
+
+ sendGeneralResponse(channel, remoteAddress, id, type, index);
+
+ return decodeTransparent(deviceSession, buf);
+
}
return null;
@@ -295,6 +329,16 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
case 0x03:
position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() * 0.1);
break;
+ case 0x56:
+ buf.readUnsignedByte(); // power level
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ break;
+ case 0x61:
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
+ break;
+ case 0x69:
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01);
+ break;
case 0x80:
position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte());
break;
@@ -351,17 +395,13 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
}
}
- private Position decodeLocation(DeviceSession deviceSession, ByteBuf buf) {
-
- Position position = new Position(getProtocolName());
- position.setDeviceId(deviceSession.getDeviceId());
-
- position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedInt()));
+ private void decodeCoordinates(Position position, ByteBuf buf) {
int status = buf.readInt();
position.set(Position.KEY_IGNITION, BitUtil.check(status, 0));
position.set(Position.KEY_BLOCKED, BitUtil.check(status, 10));
+ position.set(Position.KEY_CHARGE, BitUtil.check(status, 26));
position.setValid(BitUtil.check(status, 1));
@@ -379,19 +419,28 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
} else {
position.setLongitude(lon);
}
+ }
+
+ private double decodeCustomDouble(ByteBuf buf) {
+ int b1 = buf.readByte();
+ int b2 = buf.readUnsignedByte();
+ int sign = b1 != 0 ? b1 / Math.abs(b1) : 1;
+ return sign * (Math.abs(b1) + b2 / 255.0);
+ }
+
+ private Position decodeLocation(DeviceSession deviceSession, ByteBuf buf) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedInt()));
+
+ decodeCoordinates(position, buf);
position.setAltitude(buf.readShort());
position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort() * 0.1));
position.setCourse(buf.readUnsignedShort());
-
- DateBuilder dateBuilder = new DateBuilder(deviceSession.getTimeZone())
- .setYear(BcdUtil.readInteger(buf, 2))
- .setMonth(BcdUtil.readInteger(buf, 2))
- .setDay(BcdUtil.readInteger(buf, 2))
- .setHour(BcdUtil.readInteger(buf, 2))
- .setMinute(BcdUtil.readInteger(buf, 2))
- .setSecond(BcdUtil.readInteger(buf, 2));
- position.setTime(dateBuilder.getDate());
+ position.setTime(readDate(buf, deviceSession.get(DeviceSession.KEY_TIMEZONE)));
if (buf.readableBytes() == 20) {
@@ -411,6 +460,7 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
int subtype = buf.readUnsignedByte();
int length = buf.readUnsignedByte();
int endIndex = buf.readerIndex() + length;
+ String stringValue;
switch (subtype) {
case 0x01:
position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 100);
@@ -418,6 +468,9 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
case 0x02:
position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedShort() * 0.1);
break;
+ case 0x2b:
+ position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt());
+ break;
case 0x30:
position.set(Position.KEY_RSSI, buf.readUnsignedByte());
break;
@@ -425,12 +478,23 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
break;
case 0x33:
- String sentence = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
- if (sentence.startsWith("*M00")) {
- String lockStatus = sentence.substring(8, 8 + 7);
+ stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
+ if (stringValue.startsWith("*M00")) {
+ String lockStatus = stringValue.substring(8, 8 + 7);
position.set(Position.KEY_BATTERY, Integer.parseInt(lockStatus.substring(2, 5)) * 0.01);
}
break;
+ case 0x56:
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte() * 10);
+ buf.readUnsignedByte(); // reserved
+ break;
+ case 0x60:
+ position.set(Position.KEY_EVENT, buf.readUnsignedShort());
+ buf.skipBytes(length - 2);
+ break;
+ case 0x69:
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01);
+ break;
case 0x80:
buf.readUnsignedByte(); // content
endIndex = buf.writerIndex() - 2;
@@ -452,8 +516,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
break;
case 0x94:
if (length > 0) {
- position.set(
- Position.KEY_VIN, buf.readCharSequence(length, StandardCharsets.US_ASCII).toString());
+ stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
+ position.set(Position.KEY_VIN, stringValue);
}
break;
case 0xA7:
@@ -463,6 +527,14 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
case 0xAC:
position.set(Position.KEY_ODOMETER, buf.readUnsignedInt());
break;
+ case 0xBC:
+ stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
+ position.set("driver", stringValue.trim());
+ break;
+ case 0xBD:
+ stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, stringValue);
+ break;
case 0xD0:
long userStatus = buf.readUnsignedInt();
if (BitUtil.check(userStatus, 3)) {
@@ -473,11 +545,22 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1);
break;
case 0xD4:
- case 0xFE:
+ case 0xE1:
position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
break;
case 0xD5:
- position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01);
+ if (length == 2) {
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.01);
+ } else {
+ int count = buf.readUnsignedByte();
+ for (int i = 1; i <= count; i++) {
+ position.set("lock" + i + "Id", ByteBufUtil.hexDump(buf.readSlice(5)));
+ position.set("lock" + i + "Card", ByteBufUtil.hexDump(buf.readSlice(5)));
+ position.set("lock" + i + "Battery", buf.readUnsignedByte());
+ int status = buf.readUnsignedShort();
+ position.set("lock" + i + "Locked", !BitUtil.check(status, 5));
+ }
+ }
break;
case 0xDA:
buf.readUnsignedShort(); // string cut count
@@ -486,6 +569,14 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_MOTION, BitUtil.check(deviceStatus, 2));
position.set("cover", BitUtil.check(deviceStatus, 3));
break;
+ case 0xE6:
+ while (buf.readerIndex() < endIndex) {
+ int sensorIndex = buf.readUnsignedByte();
+ buf.skipBytes(6); // mac
+ position.set(Position.PREFIX_TEMP + sensorIndex, decodeCustomDouble(buf));
+ position.set("humidity" + sensorIndex, decodeCustomDouble(buf));
+ }
+ break;
case 0xEB:
if (buf.getUnsignedShort(buf.readerIndex()) > 200) {
Network network = new Network();
@@ -513,6 +604,16 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
case 0x00CE:
position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01);
break;
+ case 0x00D8:
+ Network network = new Network();
+ network.addCellTower(CellTower.from(
+ buf.readUnsignedShort(), buf.readUnsignedByte(),
+ buf.readUnsignedShort(), buf.readUnsignedInt()));
+ position.setNetwork(network);
+ break;
+ case 0xE1:
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ break;
default:
buf.skipBytes(extendedLength - 2);
break;
@@ -521,8 +622,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
}
break;
case 0xED:
- String license = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString().trim();
- position.set("driverLicense", license);
+ stringValue = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
+ position.set(Position.KEY_CARD, stringValue.trim());
break;
case 0xEE:
position.set(Position.KEY_RSSI, buf.readUnsignedByte());
@@ -530,6 +631,107 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.001);
position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
break;
+ case 0xF3:
+ while (buf.readerIndex() < endIndex) {
+ int extendedType = buf.readUnsignedShort();
+ int extendedLength = buf.readUnsignedByte();
+ switch (extendedType) {
+ case 0x0002:
+ position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() * 0.1);
+ break;
+ case 0x0003:
+ position.set(Position.KEY_RPM, buf.readUnsignedShort());
+ break;
+ case 0x0004:
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.001);
+ break;
+ case 0x0005:
+ position.set(Position.KEY_OBD_ODOMETER, buf.readUnsignedInt() * 100);
+ break;
+ case 0x0007:
+ position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 0.1);
+ break;
+ case 0x0008:
+ position.set(Position.KEY_ENGINE_LOAD, buf.readUnsignedShort() * 0.1);
+ break;
+ case 0x0009:
+ position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedShort() - 40);
+ break;
+ case 0x000B:
+ position.set("intakePressure", buf.readUnsignedShort());
+ break;
+ case 0x000C:
+ position.set("intakeTemp", buf.readUnsignedShort() - 40);
+ break;
+ case 0x000D:
+ position.set("intakeFlow", buf.readUnsignedShort());
+ break;
+ case 0x000E:
+ position.set(Position.KEY_THROTTLE, buf.readUnsignedShort() * 100 / 255);
+ break;
+ case 0x0050:
+ position.set(Position.KEY_VIN, buf.readSlice(17).toString(StandardCharsets.US_ASCII));
+ break;
+ case 0x0100:
+ position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedShort() * 0.1);
+ break;
+ case 0x0102:
+ position.set("tripFuel", buf.readUnsignedShort() * 0.1);
+ break;
+ case 0x0112:
+ position.set("hardAccelerationCount", buf.readUnsignedShort());
+ break;
+ case 0x0113:
+ position.set("hardDecelerationCount", buf.readUnsignedShort());
+ break;
+ case 0x0114:
+ position.set("hardCorneringCount", buf.readUnsignedShort());
+ break;
+ default:
+ buf.skipBytes(extendedLength);
+ break;
+ }
+ }
+ break;
+ case 0xFE:
+ if (length == 1) {
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ } else if (length == 2) {
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1);
+ } else {
+ int mark = buf.readUnsignedByte();
+ if (mark == 0x7C) {
+ while (buf.readerIndex() < endIndex) {
+ int extendedType = buf.readUnsignedByte();
+ int extendedLength = buf.readUnsignedByte();
+ switch (extendedType) {
+ case 0x01:
+ long alarms = buf.readUnsignedInt();
+ if (BitUtil.check(alarms, 0)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
+ }
+ if (BitUtil.check(alarms, 1)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_BRAKING);
+ }
+ if (BitUtil.check(alarms, 2)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_CORNERING);
+ }
+ if (BitUtil.check(alarms, 3)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT);
+ }
+ if (BitUtil.check(alarms, 4)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING);
+ }
+ break;
+ default:
+ buf.skipBytes(extendedLength);
+ break;
+ }
+ }
+ }
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ }
+ break;
default:
break;
}
@@ -558,7 +760,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_CHARGE, true);
}
- position.setNetwork(new Network(CellTower.fromCidLac(buf.readUnsignedInt(), buf.readUnsignedShort())));
+ position.setNetwork(new Network(CellTower.fromCidLac(
+ getConfig(), buf.readUnsignedInt(), buf.readUnsignedShort())));
int product = buf.readUnsignedByte();
int status = buf.readUnsignedShort();
@@ -583,27 +786,235 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_STATUS, status);
+ while (buf.readableBytes() > 2) {
+ int id = buf.readUnsignedByte();
+ int length = buf.readUnsignedByte();
+ switch (id) {
+ case 0x02:
+ position.setAltitude(buf.readShort());
+ break;
+ case 0x0C:
+ int x = buf.readUnsignedShort();
+ if (x > 0x8000) {
+ x -= 0x10000;
+ }
+ int y = buf.readUnsignedShort();
+ if (y > 0x8000) {
+ y -= 0x10000;
+ }
+ int z = buf.readUnsignedShort();
+ if (z > 0x8000) {
+ z -= 0x10000;
+ }
+ position.set("tilt", String.format("[%d,%d,%d]", x, y, z));
+ break;
+ default:
+ buf.skipBytes(length);
+ break;
+ }
+ }
+
return position;
}
- private List<Position> decodeLocationBatch(DeviceSession deviceSession, ByteBuf buf) {
+ private List<Position> decodeLocationBatch(DeviceSession deviceSession, ByteBuf buf, int type) {
List<Position> positions = new LinkedList<>();
- int count = buf.readUnsignedShort();
- int locationType = buf.readUnsignedByte();
+ int locationType = 0;
+ if (type == MSG_LOCATION_BATCH) {
+ buf.readUnsignedShort(); // count
+ locationType = buf.readUnsignedByte();
+ }
- for (int i = 0; i < count; i++) {
- int endIndex = buf.readUnsignedShort() + buf.readerIndex();
- Position position = decodeLocation(deviceSession, buf);
+ while (buf.readableBytes() > 2) {
+ int length = type == MSG_LOCATION_BATCH_2 ? buf.readUnsignedByte() : buf.readUnsignedShort();
+ ByteBuf fragment = buf.readSlice(length);
+ Position position = decodeLocation(deviceSession, fragment);
if (locationType > 0) {
position.set(Position.KEY_ARCHIVE, true);
}
positions.add(position);
- buf.readerIndex(endIndex);
}
return positions;
}
+ private Position decodeTransparent(DeviceSession deviceSession, ByteBuf buf) {
+
+ int type = buf.readUnsignedByte();
+
+ if (type == 0xF0) {
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ Date time = readDate(buf, deviceSession.get(DeviceSession.KEY_TIMEZONE));
+
+ if (buf.readUnsignedByte() > 0) {
+ position.set(Position.KEY_ARCHIVE, true);
+ }
+
+ buf.readUnsignedByte(); // vehicle type
+
+ int count;
+ int subtype = buf.readUnsignedByte();
+ switch (subtype) {
+ case 0x01:
+ count = buf.readUnsignedByte();
+ for (int i = 0; i < count; i++) {
+ int id = buf.readUnsignedShort();
+ int length = buf.readUnsignedByte();
+ switch (id) {
+ case 0x0102:
+ case 0x0528:
+ case 0x0546:
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 100);
+ break;
+ case 0x0103:
+ position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedInt() * 0.01);
+ break;
+ case 0x052A:
+ position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedShort() * 0.01);
+ break;
+ case 0x0105:
+ case 0x052C:
+ position.set(Position.KEY_FUEL_USED, buf.readUnsignedInt() * 0.01);
+ break;
+ case 0x014A:
+ case 0x0537:
+ case 0x0538:
+ case 0x0539:
+ position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort() * 0.01);
+ break;
+ case 0x052B:
+ position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte());
+ break;
+ case 0x052D:
+ position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte() - 40);
+ break;
+ case 0x052E:
+ position.set("airTemp", buf.readUnsignedByte() - 40);
+ break;
+ case 0x0530:
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.001);
+ break;
+ case 0x0535:
+ position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() * 0.1);
+ break;
+ case 0x0536:
+ position.set(Position.KEY_RPM, buf.readUnsignedShort());
+ break;
+ case 0x053D:
+ position.set("intakePressure", buf.readUnsignedShort() * 0.1);
+ break;
+ case 0x0544:
+ position.set("liquidLevel", buf.readUnsignedByte());
+ break;
+ case 0x0547:
+ case 0x0548:
+ position.set(Position.KEY_THROTTLE, buf.readUnsignedByte());
+ break;
+ default:
+ switch (length) {
+ case 1:
+ position.set(Position.PREFIX_IO + id, buf.readUnsignedByte());
+ break;
+ case 2:
+ position.set(Position.PREFIX_IO + id, buf.readUnsignedShort());
+ break;
+ case 4:
+ position.set(Position.PREFIX_IO + id, buf.readUnsignedInt());
+ break;
+ default:
+ buf.skipBytes(length);
+ break;
+ }
+ break;
+ }
+ }
+ getLastLocation(position, time);
+ decodeCoordinates(position, buf);
+ position.setTime(time);
+ break;
+ case 0x02:
+ List<String> codes = new LinkedList<>();
+ count = buf.readUnsignedShort();
+ for (int i = 0; i < count; i++) {
+ buf.readUnsignedInt(); // system id
+ int codeCount = buf.readUnsignedShort();
+ for (int j = 0; j < codeCount; j++) {
+ buf.readUnsignedInt(); // dtc
+ buf.readUnsignedInt(); // status
+ codes.add(buf.readCharSequence(
+ buf.readUnsignedShort(), StandardCharsets.US_ASCII).toString().trim());
+ }
+ }
+ position.set(Position.KEY_DTCS, String.join(" ", codes));
+ getLastLocation(position, time);
+ decodeCoordinates(position, buf);
+ position.setTime(time);
+ break;
+ case 0x03:
+ count = buf.readUnsignedByte();
+ for (int i = 0; i < count; i++) {
+ int id = buf.readUnsignedByte();
+ int length = buf.readUnsignedByte();
+ switch (id) {
+ case 0x01:
+ position.set(Position.KEY_ALARM, Position.ALARM_POWER_RESTORED);
+ break;
+ case 0x02:
+ position.set(Position.KEY_ALARM, Position.ALARM_POWER_CUT);
+ break;
+ case 0x1A:
+ position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
+ break;
+ case 0x1B:
+ position.set(Position.KEY_ALARM, Position.ALARM_BRAKING);
+ break;
+ case 0x1C:
+ position.set(Position.KEY_ALARM, Position.ALARM_CORNERING);
+ break;
+ case 0x1D:
+ case 0x1E:
+ case 0x1F:
+ position.set(Position.KEY_ALARM, Position.ALARM_LANE_CHANGE);
+ break;
+ case 0x23:
+ position.set(Position.KEY_ALARM, Position.ALARM_FATIGUE_DRIVING);
+ break;
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT);
+ break;
+ case 0x31:
+ case 0x32:
+ position.set(Position.KEY_ALARM, Position.ALARM_DOOR);
+ break;
+ default:
+ break;
+ }
+ buf.skipBytes(length);
+ }
+ getLastLocation(position, time);
+ decodeCoordinates(position, buf);
+ position.setTime(time);
+ break;
+ case 0x0B:
+ if (buf.readUnsignedByte() > 0) {
+ position.set(Position.KEY_VIN, buf.readCharSequence(17, StandardCharsets.US_ASCII).toString());
+ }
+ getLastLocation(position, time);
+ break;
+ default:
+ return null;
+ }
+
+ return position;
+ }
+
+ return null;
+ }
+
}
diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java
index 55c1e0c3b..ada7e3fba 100644
--- a/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/HuabaoProtocolEncoder.java
@@ -18,10 +18,11 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.traccar.BaseProtocolEncoder;
-import org.traccar.Context;
+import org.traccar.Protocol;
+import org.traccar.config.Keys;
import org.traccar.helper.DataConverter;
+import org.traccar.helper.model.AttributeUtil;
import org.traccar.model.Command;
-import org.traccar.Protocol;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -35,8 +36,8 @@ public class HuabaoProtocolEncoder extends BaseProtocolEncoder {
@Override
protected Object encodeCommand(Command command) {
- boolean alternative = Context.getIdentityManager().lookupAttributeBoolean(
- command.getDeviceId(), getProtocolName() + ".alternative", false, false, true);
+ boolean alternative = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_ALTERNATIVE.withPrefix(getProtocolName()), command.getDeviceId());
ByteBuf id = Unpooled.wrappedBuffer(
DataConverter.parseHex(getUniqueId(command.getDeviceId())));
diff --git a/src/main/java/org/traccar/protocol/HunterProProtocol.java b/src/main/java/org/traccar/protocol/HunterProProtocol.java
index 9f6424a57..64dab33b1 100644
--- a/src/main/java/org/traccar/protocol/HunterProProtocol.java
+++ b/src/main/java/org/traccar/protocol/HunterProProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class HunterProProtocol extends BaseProtocol {
- public HunterProProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public HunterProProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "\r"));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/HunterProProtocolDecoder.java b/src/main/java/org/traccar/protocol/HunterProProtocolDecoder.java
index 06bc12d59..eada1fd9a 100644
--- a/src/main/java/org/traccar/protocol/HunterProProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/HunterProProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/IdplProtocol.java b/src/main/java/org/traccar/protocol/IdplProtocol.java
index 418178756..1e44ad74c 100644
--- a/src/main/java/org/traccar/protocol/IdplProtocol.java
+++ b/src/main/java/org/traccar/protocol/IdplProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class IdplProtocol extends BaseProtocol {
- public IdplProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public IdplProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/IdplProtocolDecoder.java b/src/main/java/org/traccar/protocol/IdplProtocolDecoder.java
index cf3c03d7f..72409b168 100644
--- a/src/main/java/org/traccar/protocol/IdplProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/IdplProtocolDecoder.java
@@ -20,7 +20,7 @@ import java.util.regex.Pattern;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.Parser.CoordinateFormat;
diff --git a/src/main/java/org/traccar/protocol/IntellitracProtocol.java b/src/main/java/org/traccar/protocol/IntellitracProtocol.java
index 3abf40da7..a82e6a5db 100644
--- a/src/main/java/org/traccar/protocol/IntellitracProtocol.java
+++ b/src/main/java/org/traccar/protocol/IntellitracProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class IntellitracProtocol extends BaseProtocol {
- public IntellitracProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public IntellitracProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new IntellitracFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/IntellitracProtocolDecoder.java b/src/main/java/org/traccar/protocol/IntellitracProtocolDecoder.java
index 930d4f23b..b86584016 100644
--- a/src/main/java/org/traccar/protocol/IntellitracProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/IntellitracProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/IotmProtocol.java b/src/main/java/org/traccar/protocol/IotmProtocol.java
index f202d9b9d..1631b67d8 100644
--- a/src/main/java/org/traccar/protocol/IotmProtocol.java
+++ b/src/main/java/org/traccar/protocol/IotmProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.mqtt.MqttEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class IotmProtocol extends BaseProtocol {
- public IotmProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public IotmProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(MqttEncoder.INSTANCE);
pipeline.addLast(new MqttDecoder());
pipeline.addLast(new IotmProtocolDecoder(IotmProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java b/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java
index 9c94ffd4b..7bbe6c8de 100644
--- a/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/IotmProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2020 - 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.
@@ -25,7 +25,7 @@ import io.netty.handler.codec.mqtt.MqttMessageBuilders;
import io.netty.handler.codec.mqtt.MqttPublishMessage;
import io.netty.handler.codec.mqtt.MqttSubscribeMessage;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.UnitsConverter;
@@ -260,7 +260,7 @@ public class IotmProtocolDecoder extends BaseProtocolDecoder {
MqttSubscribeMessage message = (MqttSubscribeMessage) msg;
MqttMessage response = MqttMessageBuilders.subAck()
- .packetId((short) message.variableHeader().messageId())
+ .packetId(message.variableHeader().messageId())
.build();
if (channel != null) {
@@ -339,7 +339,7 @@ public class IotmProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedByte(); // checksum
MqttMessage response = MqttMessageBuilders.pubAck()
- .packetId((short) message.variableHeader().packetId())
+ .packetId(message.variableHeader().packetId())
.build();
if (channel != null) {
diff --git a/src/main/java/org/traccar/protocol/ItsProtocol.java b/src/main/java/org/traccar/protocol/ItsProtocol.java
index 45df3da11..7d59ea60c 100644
--- a/src/main/java/org/traccar/protocol/ItsProtocol.java
+++ b/src/main/java/org/traccar/protocol/ItsProtocol.java
@@ -20,17 +20,21 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class ItsProtocol extends BaseProtocol {
- public ItsProtocol() {
+ @Inject
+ public ItsProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new ItsFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java b/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java
index 9eed58347..8a8d734cf 100644
--- a/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ItsProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
@@ -205,7 +205,8 @@ public class ItsProtocolDecoder extends BaseProtocolDecoder {
if (parser.hasNext()) {
position.setValid(parser.nextInt() == 1);
}
- position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+ position.setTime(parser.nextDateTime(
+ Parser.DateTimeFormat.DMY_HMS, getTimeZone(deviceSession.getDeviceId()).getID()));
if (parser.hasNext()) {
position.setValid(parser.next().matches("[1A]"));
}
diff --git a/src/main/java/org/traccar/protocol/Ivt401Protocol.java b/src/main/java/org/traccar/protocol/Ivt401Protocol.java
index fb44e4fe9..5132c7467 100644
--- a/src/main/java/org/traccar/protocol/Ivt401Protocol.java
+++ b/src/main/java/org/traccar/protocol/Ivt401Protocol.java
@@ -20,13 +20,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Ivt401Protocol extends BaseProtocol {
- public Ivt401Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Ivt401Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ';'));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new Ivt401ProtocolDecoder(Ivt401Protocol.this));
diff --git a/src/main/java/org/traccar/protocol/Ivt401ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Ivt401ProtocolDecoder.java
index 63556e7a9..972f22ebe 100644
--- a/src/main/java/org/traccar/protocol/Ivt401ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Ivt401ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/JidoProtocol.java b/src/main/java/org/traccar/protocol/JidoProtocol.java
index 2a2e71dbe..b30cc586a 100644
--- a/src/main/java/org/traccar/protocol/JidoProtocol.java
+++ b/src/main/java/org/traccar/protocol/JidoProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class JidoProtocol extends BaseProtocol {
- public JidoProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public JidoProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/JidoProtocolDecoder.java b/src/main/java/org/traccar/protocol/JidoProtocolDecoder.java
index 40fa8864d..98fb36e11 100644
--- a/src/main/java/org/traccar/protocol/JidoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/JidoProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/JpKorjarProtocol.java b/src/main/java/org/traccar/protocol/JpKorjarProtocol.java
index fe5b2480d..ae312ea3e 100644
--- a/src/main/java/org/traccar/protocol/JpKorjarProtocol.java
+++ b/src/main/java/org/traccar/protocol/JpKorjarProtocol.java
@@ -1,6 +1,6 @@
/*
+ * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2016 Nyash (nyashh@gmail.com)
- * Copyright 2018 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class JpKorjarProtocol extends BaseProtocol {
- public JpKorjarProtocol() {
- addServer(new TrackerServer(false, this.getName()) {
+ @Inject
+ public JpKorjarProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new JpKorjarFrameDecoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new JpKorjarProtocolDecoder(JpKorjarProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/JpKorjarProtocolDecoder.java b/src/main/java/org/traccar/protocol/JpKorjarProtocolDecoder.java
index 33026918a..ffddcc568 100644
--- a/src/main/java/org/traccar/protocol/JpKorjarProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/JpKorjarProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java b/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java
index bfefb94a7..f7890f814 100644
--- a/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java
+++ b/src/main/java/org/traccar/protocol/Jt600FrameDecoder.java
@@ -35,7 +35,7 @@ public class Jt600FrameDecoder extends BaseFrameDecoder {
char type = (char) buf.getByte(buf.readerIndex());
if (type == '$') {
- boolean longFormat = Jt600ProtocolDecoder.isLongFormat(buf, buf.readerIndex() + 1);
+ boolean longFormat = Jt600ProtocolDecoder.isLongFormat(buf);
int length = buf.getUnsignedShort(buf.readerIndex() + (longFormat ? 8 : 7)) + 10;
if (length <= buf.readableBytes()) {
return buf.readRetainedSlice(length);
diff --git a/src/main/java/org/traccar/protocol/Jt600Protocol.java b/src/main/java/org/traccar/protocol/Jt600Protocol.java
index 37c82f741..9dc62662f 100644
--- a/src/main/java/org/traccar/protocol/Jt600Protocol.java
+++ b/src/main/java/org/traccar/protocol/Jt600Protocol.java
@@ -19,19 +19,23 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class Jt600Protocol extends BaseProtocol {
- public Jt600Protocol() {
+ @Inject
+ public Jt600Protocol(Config config) {
setSupportedDataCommands(
Command.TYPE_ENGINE_RESUME,
Command.TYPE_ENGINE_STOP,
Command.TYPE_SET_TIMEZONE,
Command.TYPE_REBOOT_DEVICE);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new Jt600FrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new Jt600ProtocolEncoder(Jt600Protocol.this));
diff --git a/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java
index b4b70091b..dc763dea7 100644
--- a/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BcdUtil;
@@ -86,8 +86,8 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
}
- static boolean isLongFormat(ByteBuf buf, int flagIndex) {
- return buf.getUnsignedByte(flagIndex) >> 4 >= 7;
+ static boolean isLongFormat(ByteBuf buf) {
+ return buf.getUnsignedByte(buf.readerIndex() + 8) == 0;
}
static void decodeBinaryLocation(ByteBuf buf, Position position) {
@@ -123,9 +123,9 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
List<Position> positions = new LinkedList<>();
- buf.readByte(); // header
+ boolean longFormat = isLongFormat(buf);
- boolean longFormat = isLongFormat(buf, buf.readerIndex());
+ buf.readByte(); // header
String id = String.valueOf(Long.parseLong(ByteBufUtil.hexDump(buf.readSlice(5))));
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id);
@@ -143,7 +143,7 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
boolean responseRequired = false;
- while (buf.readableBytes() > 1) {
+ while (buf.readableBytes() >= 17) {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
@@ -177,7 +177,8 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_BATTERY_LEVEL, battery);
}
- CellTower cellTower = CellTower.fromCidLac(buf.readUnsignedShort(), buf.readUnsignedShort());
+ CellTower cellTower = CellTower.fromCidLac(
+ getConfig(), buf.readUnsignedShort(), buf.readUnsignedShort());
cellTower.setSignalStrength((int) buf.readUnsignedByte());
position.setNetwork(new Network(cellTower));
@@ -201,7 +202,7 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
int rssi = buf.readUnsignedByte();
if (cid != 0 && lac != 0) {
- CellTower cellTower = CellTower.fromCidLac(cid, lac);
+ CellTower cellTower = CellTower.fromCidLac(getConfig(), cid, lac);
cellTower.setSignalStrength(rssi);
position.setNetwork(new Network(cellTower));
} else {
@@ -356,7 +357,7 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt(0));
position.set(Position.KEY_STATUS, parser.nextBinInt(0));
- CellTower cellTower = CellTower.fromCidLac(parser.nextInt(0), parser.nextInt(0));
+ CellTower cellTower = CellTower.fromCidLac(getConfig(), parser.nextInt(0), parser.nextInt(0));
cellTower.setSignalStrength(parser.nextInt(0));
position.setNetwork(new Network(cellTower));
diff --git a/src/main/java/org/traccar/protocol/KenjiProtocol.java b/src/main/java/org/traccar/protocol/KenjiProtocol.java
index 90c0c511c..b4e610cbd 100644
--- a/src/main/java/org/traccar/protocol/KenjiProtocol.java
+++ b/src/main/java/org/traccar/protocol/KenjiProtocol.java
@@ -22,13 +22,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class KenjiProtocol extends BaseProtocol {
- public KenjiProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public KenjiProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/KenjiProtocolDecoder.java b/src/main/java/org/traccar/protocol/KenjiProtocolDecoder.java
index 63812242a..fb989c72e 100644
--- a/src/main/java/org/traccar/protocol/KenjiProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/KenjiProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/KhdProtocol.java b/src/main/java/org/traccar/protocol/KhdProtocol.java
index 60a2aea7f..add13ef16 100644
--- a/src/main/java/org/traccar/protocol/KhdProtocol.java
+++ b/src/main/java/org/traccar/protocol/KhdProtocol.java
@@ -19,11 +19,15 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class KhdProtocol extends BaseProtocol {
- public KhdProtocol() {
+ @Inject
+ public KhdProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME,
@@ -33,9 +37,9 @@ public class KhdProtocol extends BaseProtocol {
Command.TYPE_SET_ODOMETER,
Command.TYPE_POSITION_SINGLE);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(512, 3, 2));
pipeline.addLast(new KhdProtocolEncoder(KhdProtocol.this));
pipeline.addLast(new KhdProtocolDecoder(KhdProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java b/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java
index a14f9b8a4..dd2e1dbfd 100644
--- a/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BcdUtil;
@@ -205,6 +205,9 @@ public class KhdProtocolDecoder extends BaseProtocolDecoder {
}
}
break;
+ case 0x20:
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ break;
case 0x23:
Network network = new Network();
int count = buf.readUnsignedByte();
diff --git a/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java b/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java
index 8aeb9660d..12353b415 100644
--- a/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/KhdProtocolEncoder.java
@@ -84,7 +84,7 @@ public class KhdProtocolEncoder extends BaseProtocolEncoder {
return encodeCommand(MSG_FACTORY_RESET, uniqueId, null);
case Command.TYPE_SET_SPEED_LIMIT:
ByteBuf content = Unpooled.buffer();
- content.writeByte(Integer.parseInt(command.getString(Command.KEY_DATA)));
+ content.writeByte(command.getInteger(Command.KEY_DATA));
return encodeCommand(MSG_RESUME_OIL, uniqueId, content);
case Command.TYPE_SET_ODOMETER:
return encodeCommand(MSG_DELETE_MILEAGE, uniqueId, null);
diff --git a/src/main/java/org/traccar/protocol/L100Protocol.java b/src/main/java/org/traccar/protocol/L100Protocol.java
index 942029307..fa6d1b07e 100644
--- a/src/main/java/org/traccar/protocol/L100Protocol.java
+++ b/src/main/java/org/traccar/protocol/L100Protocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class L100Protocol extends BaseProtocol {
- public L100Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public L100Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new L100FrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/L100ProtocolDecoder.java b/src/main/java/org/traccar/protocol/L100ProtocolDecoder.java
index 5b5eb7d60..820de8f1c 100644
--- a/src/main/java/org/traccar/protocol/L100ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/L100ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Checksum;
diff --git a/src/main/java/org/traccar/protocol/LacakProtocol.java b/src/main/java/org/traccar/protocol/LacakProtocol.java
index 0a0499ad7..ddaf5078d 100644
--- a/src/main/java/org/traccar/protocol/LacakProtocol.java
+++ b/src/main/java/org/traccar/protocol/LacakProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class LacakProtocol extends BaseProtocol {
- public LacakProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public LacakProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(16384));
diff --git a/src/main/java/org/traccar/protocol/LacakProtocolDecoder.java b/src/main/java/org/traccar/protocol/LacakProtocolDecoder.java
index 132087c8f..66aab3490 100644
--- a/src/main/java/org/traccar/protocol/LacakProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/LacakProtocolDecoder.java
@@ -19,13 +19,13 @@ import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateUtil;
import org.traccar.model.Position;
-import javax.json.Json;
-import javax.json.JsonObject;
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
import java.io.StringReader;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
diff --git a/src/main/java/org/traccar/protocol/LaipacProtocol.java b/src/main/java/org/traccar/protocol/LaipacProtocol.java
index 1d561dbd2..65b1a57e9 100644
--- a/src/main/java/org/traccar/protocol/LaipacProtocol.java
+++ b/src/main/java/org/traccar/protocol/LaipacProtocol.java
@@ -18,23 +18,27 @@ package org.traccar.protocol;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
-import org.traccar.model.Command;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+import org.traccar.model.Command;
+
+import jakarta.inject.Inject;
public class LaipacProtocol extends BaseProtocol {
- public LaipacProtocol() {
+ @Inject
+ public LaipacProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_POSITION_SINGLE,
Command.TYPE_REBOOT_DEVICE);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java
index 45890e9a2..5745909c7 100644
--- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java
@@ -17,8 +17,8 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.helper.model.AttributeUtil;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Checksum;
@@ -28,6 +28,8 @@ import org.traccar.helper.PatternBuilder;
import org.traccar.model.CellTower;
import org.traccar.model.Network;
import org.traccar.model.Position;
+import org.traccar.model.Device;
+import org.traccar.helper.BitUtil;
import java.net.SocketAddress;
import java.util.regex.Pattern;
@@ -108,19 +110,31 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder {
}
}
- private String decodeEvent(String event, Position position) {
+ private String decodeEvent(String event, Position position, String model) {
if (event.length() == 1) {
char inputStatus = event.charAt(0);
if (inputStatus >= 'A' && inputStatus <= 'D') {
int inputStatusInt = inputStatus - 'A';
- position.set(Position.PREFIX_IN + 1, inputStatusInt & 1);
- position.set(Position.PREFIX_IN + 2, inputStatusInt & 2);
+ position.set(Position.PREFIX_IN + 1, (boolean) BitUtil.check(inputStatusInt, 0));
+ position.set(Position.PREFIX_IN + 2, (boolean) BitUtil.check(inputStatusInt, 1));
+ if ("SF-Lite".equals(model)) {
+ position.set(Position.PREFIX_IN + 3, false);
+ }
+ return null;
+ } else if (inputStatus >= 'O' && inputStatus <= 'R') {
+ int inputStatusInt = inputStatus - 'O';
+ position.set(Position.PREFIX_IN + 1, (boolean) BitUtil.check(inputStatusInt, 0));
+ position.set(Position.PREFIX_IN + 2, (boolean) BitUtil.check(inputStatusInt, 1));
+ if ("SF-Lite".equals(model)) {
+ position.set(Position.PREFIX_IN + 3, true);
+ }
return null;
}
}
return event;
+
}
private void sendEventResponse(
@@ -132,6 +146,9 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder {
case "3":
responseCode = "d";
break;
+ case "M":
+ responseCode = "m";
+ break;
case "S":
case "T":
responseCode = "t";
@@ -209,6 +226,8 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder {
return null;
}
+ String model = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()).getModel();
+
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
@@ -230,12 +249,17 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder {
String event = parser.next();
position.set(Position.KEY_ALARM, decodeAlarm(event));
- position.set(Position.KEY_EVENT, decodeEvent(event, position));
+ position.set(Position.KEY_EVENT, decodeEvent(event, position, model));
position.set(Position.KEY_BATTERY, Double.parseDouble(parser.next().replaceAll("\\.", "")) * 0.001);
position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
position.set(Position.KEY_GPS, parser.nextInt());
position.set(Position.PREFIX_ADC + 1, parser.nextDouble() * 0.001);
- position.set(Position.PREFIX_ADC + 2, parser.nextDouble() * 0.001);
+
+ if ("AVL110".equals(model) || "AVL120".equals(model)) {
+ position.set(Position.PREFIX_ADC + 2, parser.nextDouble() * 0.001);
+ } else {
+ parser.next();
+ }
Integer lac = parser.nextHexInt();
Integer cid = parser.nextHexInt();
@@ -253,8 +277,8 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder {
sendAcknowledge(status, event, checksum, channel, remoteAddress);
- String devicePassword = Context.getIdentityManager()
- .getDevicePassword(deviceSession.getDeviceId(), getProtocolName(), DEFAULT_DEVICE_PASSWORD);
+ String devicePassword = AttributeUtil.getDevicePassword(
+ getCacheManager(), deviceSession.getDeviceId(), getProtocolName(), DEFAULT_DEVICE_PASSWORD);
sendEventResponse(event, devicePassword, channel, remoteAddress);
}
diff --git a/src/main/java/org/traccar/protocol/LeafSpyProtocol.java b/src/main/java/org/traccar/protocol/LeafSpyProtocol.java
index 05f63a2d7..9e167e7ba 100644
--- a/src/main/java/org/traccar/protocol/LeafSpyProtocol.java
+++ b/src/main/java/org/traccar/protocol/LeafSpyProtocol.java
@@ -22,13 +22,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class LeafSpyProtocol extends BaseProtocol {
- public LeafSpyProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public LeafSpyProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(16384));
diff --git a/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java b/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java
index ad0c9bd32..6affb85c5 100644
--- a/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/LeafSpyProtocolDecoder.java
@@ -22,7 +22,7 @@ import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.QueryStringDecoder;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.model.Position;
diff --git a/src/main/java/org/traccar/protocol/M2cProtocol.java b/src/main/java/org/traccar/protocol/M2cProtocol.java
index 9de8526c3..8abc30f60 100644
--- a/src/main/java/org/traccar/protocol/M2cProtocol.java
+++ b/src/main/java/org/traccar/protocol/M2cProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class M2cProtocol extends BaseProtocol {
- public M2cProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public M2cProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(32 * 1024, ']'));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/M2cProtocolDecoder.java b/src/main/java/org/traccar/protocol/M2cProtocolDecoder.java
index 1460bb176..9415d0f07 100644
--- a/src/main/java/org/traccar/protocol/M2cProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/M2cProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/M2mProtocol.java b/src/main/java/org/traccar/protocol/M2mProtocol.java
index dda328a59..03a069d66 100644
--- a/src/main/java/org/traccar/protocol/M2mProtocol.java
+++ b/src/main/java/org/traccar/protocol/M2mProtocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.FixedLengthFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class M2mProtocol extends BaseProtocol {
- public M2mProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public M2mProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new FixedLengthFrameDecoder(23));
pipeline.addLast(new M2mProtocolDecoder(M2mProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/M2mProtocolDecoder.java b/src/main/java/org/traccar/protocol/M2mProtocolDecoder.java
index 21e4a2fd0..7eca93a59 100644
--- a/src/main/java/org/traccar/protocol/M2mProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/M2mProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.model.Position;
diff --git a/src/main/java/org/traccar/protocol/MaestroProtocol.java b/src/main/java/org/traccar/protocol/MaestroProtocol.java
index 87453ce7d..29f0b8897 100644
--- a/src/main/java/org/traccar/protocol/MaestroProtocol.java
+++ b/src/main/java/org/traccar/protocol/MaestroProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class MaestroProtocol extends BaseProtocol {
- public MaestroProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public MaestroProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new FixedLengthFrameDecoder(160));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/MaestroProtocolDecoder.java b/src/main/java/org/traccar/protocol/MaestroProtocolDecoder.java
index 37b097414..78308658e 100644
--- a/src/main/java/org/traccar/protocol/MaestroProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MaestroProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/ManPowerProtocol.java b/src/main/java/org/traccar/protocol/ManPowerProtocol.java
index 49d8b1e9f..ba2414ca7 100644
--- a/src/main/java/org/traccar/protocol/ManPowerProtocol.java
+++ b/src/main/java/org/traccar/protocol/ManPowerProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class ManPowerProtocol extends BaseProtocol {
- public ManPowerProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public ManPowerProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ';'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/ManPowerProtocolDecoder.java b/src/main/java/org/traccar/protocol/ManPowerProtocolDecoder.java
index 2c7b7eb40..8ac13b4d4 100644
--- a/src/main/java/org/traccar/protocol/ManPowerProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ManPowerProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/Mavlink2Protocol.java b/src/main/java/org/traccar/protocol/Mavlink2Protocol.java
index d779648e4..916fb7467 100644
--- a/src/main/java/org/traccar/protocol/Mavlink2Protocol.java
+++ b/src/main/java/org/traccar/protocol/Mavlink2Protocol.java
@@ -15,18 +15,21 @@
*/
package org.traccar.protocol;
+import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
-import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
+import jakarta.inject.Inject;
public class Mavlink2Protocol extends BaseProtocol {
- public Mavlink2Protocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public Mavlink2Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 1, 1, 10, 0));
pipeline.addLast(new Mavlink2ProtocolDecoder(Mavlink2Protocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/Mavlink2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Mavlink2ProtocolDecoder.java
index 431258388..fac930ba8 100644
--- a/src/main/java/org/traccar/protocol/Mavlink2ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Mavlink2ProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
diff --git a/src/main/java/org/traccar/protocol/MegastekProtocol.java b/src/main/java/org/traccar/protocol/MegastekProtocol.java
index e9f5f9fde..9f8937f01 100644
--- a/src/main/java/org/traccar/protocol/MegastekProtocol.java
+++ b/src/main/java/org/traccar/protocol/MegastekProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class MegastekProtocol extends BaseProtocol {
- public MegastekProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public MegastekProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new MegastekFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/MegastekProtocolDecoder.java b/src/main/java/org/traccar/protocol/MegastekProtocolDecoder.java
index 7233280c2..06b6f0e76 100644
--- a/src/main/java/org/traccar/protocol/MegastekProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MegastekProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocol.java b/src/main/java/org/traccar/protocol/MeiligaoProtocol.java
index e8a66e49f..d86a00fb3 100644
--- a/src/main/java/org/traccar/protocol/MeiligaoProtocol.java
+++ b/src/main/java/org/traccar/protocol/MeiligaoProtocol.java
@@ -18,31 +18,36 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class MeiligaoProtocol extends BaseProtocol {
- public MeiligaoProtocol() {
+ @Inject
+ public MeiligaoProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_POSITION_SINGLE,
Command.TYPE_POSITION_PERIODIC,
+ Command.TYPE_OUTPUT_CONTROL,
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME,
Command.TYPE_ALARM_GEOFENCE,
Command.TYPE_SET_TIMEZONE,
Command.TYPE_REQUEST_PHOTO,
Command.TYPE_REBOOT_DEVICE);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new MeiligaoFrameDecoder());
pipeline.addLast(new MeiligaoProtocolEncoder(MeiligaoProtocol.this));
pipeline.addLast(new MeiligaoProtocolDecoder(MeiligaoProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new MeiligaoProtocolEncoder(MeiligaoProtocol.this));
pipeline.addLast(new MeiligaoProtocolDecoder(MeiligaoProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java
index d38e5d1c3..1f8c4d2da 100644
--- a/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MeiligaoProtocolDecoder.java
@@ -19,8 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -40,7 +39,7 @@ import java.util.regex.Pattern;
public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
- private Map<Byte, ByteBuf> photos = new HashMap<>();
+ private final Map<Byte, ByteBuf> photos = new HashMap<>();
public MeiligaoProtocolDecoder(Protocol protocol) {
super(protocol);
@@ -283,7 +282,7 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_RSSI, parser.nextHexInt());
position.set(Position.KEY_ODOMETER, parser.nextHexLong());
position.set(Position.KEY_SATELLITES, parser.nextHexInt());
- position.set("driverLicense", parser.next());
+ position.set(Position.KEY_CARD, parser.next());
position.set(Position.KEY_ODOMETER, parser.nextLong());
position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next());
@@ -469,10 +468,9 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
} else if (command == MSG_POSITION_IMAGE) {
byte imageIndex = buf.readByte();
buf.readUnsignedByte(); // image upload type
- String uniqueId = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getUniqueId();
ByteBuf photo = photos.remove(imageIndex);
try {
- position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(uniqueId, photo, "jpg"));
+ position.set(Position.KEY_IMAGE, writeMediaFile(deviceSession.getUniqueId(), photo, "jpg"));
} finally {
photo.release();
}
diff --git a/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java b/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java
index e5b2cf4e7..5859d91ce 100644
--- a/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/MeiligaoProtocolEncoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -18,13 +18,16 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.traccar.BaseProtocolEncoder;
-import org.traccar.Context;
+import org.traccar.Protocol;
+import org.traccar.config.Keys;
import org.traccar.helper.Checksum;
import org.traccar.helper.DataConverter;
+import org.traccar.helper.model.AttributeUtil;
import org.traccar.model.Command;
-import org.traccar.Protocol;
+import org.traccar.model.Device;
import java.nio.charset.StandardCharsets;
+import java.util.Set;
import java.util.TimeZone;
public class MeiligaoProtocolEncoder extends BaseProtocolEncoder {
@@ -56,15 +59,36 @@ public class MeiligaoProtocolEncoder extends BaseProtocolEncoder {
return buf;
}
- @Override
- protected Object encodeCommand(Command command) {
+ private ByteBuf encodeOutputCommand(long deviceId, int index, int value) {
- boolean alternative = Context.getIdentityManager().lookupAttributeBoolean(
- command.getDeviceId(), getProtocolName() + ".alternative", false, false, true);
+ int outputCount;
+ int outputType;
- int outputControlMessageType = alternative
- ? MeiligaoProtocolDecoder.MSG_OUTPUT_CONTROL_1
- : MeiligaoProtocolDecoder.MSG_OUTPUT_CONTROL_2;
+ String model = getCacheManager().getObject(Device.class, deviceId).getModel();
+
+ if (model != null && Set.of("TK510", "GT08", "TK208", "TK228", "MT05").contains(model)) {
+ outputCount = 5;
+ outputType = MeiligaoProtocolDecoder.MSG_OUTPUT_CONTROL_1;
+ } else {
+ outputCount = 1;
+ boolean alternative = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_ALTERNATIVE.withPrefix(getProtocolName()), deviceId);
+ outputType = alternative
+ ? MeiligaoProtocolDecoder.MSG_OUTPUT_CONTROL_1
+ : MeiligaoProtocolDecoder.MSG_OUTPUT_CONTROL_2;
+ }
+
+ ByteBuf content = Unpooled.buffer();
+
+ for (int i = 1; i <= outputCount; i++) {
+ content.writeByte(i == index ? value : 2);
+ }
+
+ return encodeContent(deviceId, outputType, content);
+ }
+
+ @Override
+ protected Object encodeCommand(Command command) {
ByteBuf content = Unpooled.buffer();
@@ -74,12 +98,14 @@ public class MeiligaoProtocolEncoder extends BaseProtocolEncoder {
case Command.TYPE_POSITION_PERIODIC:
content.writeShort(command.getInteger(Command.KEY_FREQUENCY) / 10);
return encodeContent(command.getDeviceId(), MeiligaoProtocolDecoder.MSG_TRACK_BY_INTERVAL, content);
+ case Command.TYPE_OUTPUT_CONTROL:
+ int index = command.getInteger(Command.KEY_INDEX) - 1;
+ int value = command.getInteger(Command.KEY_DATA);
+ return encodeOutputCommand(command.getDeviceId(), index, value);
case Command.TYPE_ENGINE_STOP:
- content.writeByte(0x01);
- return encodeContent(command.getDeviceId(), outputControlMessageType, content);
+ return encodeOutputCommand(command.getDeviceId(), 1, 1);
case Command.TYPE_ENGINE_RESUME:
- content.writeByte(0x00);
- return encodeContent(command.getDeviceId(), outputControlMessageType, content);
+ return encodeOutputCommand(command.getDeviceId(), 1, 0);
case Command.TYPE_ALARM_GEOFENCE:
content.writeShort(command.getInteger(Command.KEY_RADIUS));
return encodeContent(command.getDeviceId(), MeiligaoProtocolDecoder.MSG_MOVEMENT_ALARM, content);
diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocol.java b/src/main/java/org/traccar/protocol/MeitrackProtocol.java
index 7439ea611..4109b22c9 100644
--- a/src/main/java/org/traccar/protocol/MeitrackProtocol.java
+++ b/src/main/java/org/traccar/protocol/MeitrackProtocol.java
@@ -19,11 +19,15 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class MeitrackProtocol extends BaseProtocol {
- public MeitrackProtocol() {
+ @Inject
+ public MeitrackProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_POSITION_SINGLE,
Command.TYPE_ENGINE_STOP,
@@ -32,18 +36,18 @@ public class MeitrackProtocol extends BaseProtocol {
Command.TYPE_ALARM_DISARM,
Command.TYPE_REQUEST_PHOTO,
Command.TYPE_SEND_SMS);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new MeitrackFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new MeitrackProtocolEncoder(MeitrackProtocol.this));
pipeline.addLast(new MeitrackProtocolDecoder(MeitrackProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new MeitrackProtocolEncoder(MeitrackProtocol.this));
pipeline.addLast(new MeitrackProtocolDecoder(MeitrackProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java
index a9cc1de3a..0f0d22021 100644
--- a/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MeitrackProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,8 +19,8 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.model.Device;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Checksum;
@@ -204,18 +204,18 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.PREFIX_ADC + i, parser.nextHexInt());
}
- String deviceModel = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getModel();
- if (deviceModel == null) {
- deviceModel = "";
+ String model = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()).getModel();
+ if (model == null) {
+ model = "";
}
- switch (deviceModel.toUpperCase()) {
+ switch (model.toUpperCase()) {
case "MVT340":
case "MVT380":
- position.set(Position.KEY_BATTERY, parser.nextHexInt(0) * 3.0 * 2.0 / 1024.0);
+ position.set(Position.KEY_BATTERY, parser.nextHexInt() * 3.0 * 2.0 / 1024.0);
position.set(Position.KEY_POWER, parser.nextHexInt(0) * 3.0 * 16.0 / 1024.0);
break;
case "MT90":
- position.set(Position.KEY_BATTERY, parser.nextHexInt(0) * 3.3 * 2.0 / 4096.0);
+ position.set(Position.KEY_BATTERY, parser.nextHexInt() * 3.3 * 2.0 / 4096.0);
position.set(Position.KEY_POWER, parser.nextHexInt(0));
break;
case "T1":
@@ -225,19 +225,18 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
case "MVT800":
case "TC68":
case "TC68S":
- position.set(Position.KEY_BATTERY, parser.nextHexInt(0) * 3.3 * 2.0 / 4096.0);
+ position.set(Position.KEY_BATTERY, parser.nextHexInt() * 3.3 * 2.0 / 4096.0);
position.set(Position.KEY_POWER, parser.nextHexInt(0) * 3.3 * 16.0 / 4096.0);
break;
case "T311":
case "T322X":
case "T333":
case "T355":
- position.set(Position.KEY_BATTERY, parser.nextHexInt(0) / 100.0);
- position.set(Position.KEY_POWER, parser.nextHexInt(0) / 100.0);
- break;
+ case "T366":
+ case "T366G":
default:
- position.set(Position.KEY_BATTERY, parser.nextHexInt(0));
- position.set(Position.KEY_POWER, parser.nextHexInt(0));
+ position.set(Position.KEY_BATTERY, parser.nextHexInt() / 100.0);
+ position.set(Position.KEY_POWER, parser.nextHexInt(0) / 100.0);
break;
}
@@ -368,13 +367,9 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
StringBuilder command = new StringBuilder("@@");
command.append(flag).append(27 + positions.size() / 10).append(",");
command.append(imei).append(",CCC,").append(positions.size()).append("*");
- int checksum = 0;
- for (int i = 0; i < command.length(); i += 1) {
- checksum += command.charAt(i);
- }
- command.append(String.format("%02x", checksum & 0xff).toUpperCase());
+ command.append(Checksum.sum(command.toString()));
command.append("\r\n");
- channel.writeAndFlush(new NetworkMessage(command.toString(), remoteAddress)); // delete processed data
+ channel.writeAndFlush(new NetworkMessage(command.toString(), remoteAddress));
}
return positions;
@@ -404,7 +399,8 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
int paramCount = buf.readUnsignedByte();
for (int j = 0; j < paramCount; j++) {
- int id = buf.readUnsignedByte();
+ boolean extension = buf.getUnsignedByte(buf.readerIndex()) == 0xFE;
+ int id = extension ? buf.readUnsignedShort() : buf.readUnsignedByte();
switch (id) {
case 0x01:
position.set(Position.KEY_EVENT, buf.readUnsignedByte());
@@ -424,12 +420,21 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
case 0x15:
position.set(Position.KEY_INPUT, buf.readUnsignedByte());
break;
+ case 0x47:
+ int lockState = buf.readUnsignedByte();
+ if (lockState > 0) {
+ position.set(Position.KEY_LOCK, lockState == 2);
+ }
+ break;
case 0x97:
position.set(Position.KEY_THROTTLE, buf.readUnsignedByte());
break;
case 0x9D:
position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte());
break;
+ case 0xFE69:
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ break;
default:
buf.readUnsignedByte();
break;
@@ -438,7 +443,8 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
paramCount = buf.readUnsignedByte();
for (int j = 0; j < paramCount; j++) {
- int id = buf.readUnsignedByte();
+ boolean extension = buf.getUnsignedByte(buf.readerIndex()) == 0xFE;
+ int id = extension ? buf.readUnsignedShort() : buf.readUnsignedByte();
switch (id) {
case 0x08:
position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE()));
@@ -491,7 +497,8 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
paramCount = buf.readUnsignedByte();
for (int j = 0; j < paramCount; j++) {
- int id = buf.readUnsignedByte();
+ boolean extension = buf.getUnsignedByte(buf.readerIndex()) == 0xFE;
+ int id = extension ? buf.readUnsignedShort() : buf.readUnsignedByte();
switch (id) {
case 0x02:
position.setLatitude(buf.readIntLE() * 0.000001);
@@ -509,6 +516,9 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
case 0x0D:
position.set("runtime", buf.readUnsignedIntLE());
break;
+ case 0x25:
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, String.valueOf(buf.readUnsignedIntLE()));
+ break;
case 0xA0:
position.set(Position.KEY_FUEL_USED, buf.readUnsignedIntLE() * 0.001);
break;
@@ -523,8 +533,41 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
paramCount = buf.readUnsignedByte();
for (int j = 0; j < paramCount; j++) {
- buf.readUnsignedByte(); // id
- buf.skipBytes(buf.readUnsignedByte()); // value
+ boolean extension = buf.getUnsignedByte(buf.readerIndex()) == 0xFE;
+ int id = extension ? buf.readUnsignedShort() : buf.readUnsignedByte();
+ int length = buf.readUnsignedByte();
+ switch (id) {
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2D:
+ case 0x2E:
+ case 0x2F:
+ case 0x30:
+ case 0x31:
+ buf.readUnsignedByte(); // label
+ position.set(Position.PREFIX_TEMP + (id - 0x2A), buf.readShortLE() * 0.01);
+ break;
+ case 0xFE31:
+ buf.readUnsignedByte(); // alarm protocol
+ buf.readUnsignedByte(); // alarm type
+ buf.skipBytes(length - 2);
+ break;
+ case 0xFEA8:
+ for (int k = 1; k <= 3; k++) {
+ if (buf.readUnsignedByte() > 0) {
+ String key = k == 1 ? Position.KEY_BATTERY_LEVEL : "battery" + k + "Level";
+ position.set(key, buf.readUnsignedByte());
+ } else {
+ buf.readUnsignedByte();
+ }
+ }
+ buf.readUnsignedByte(); // battery alert
+ break;
+ default:
+ buf.skipBytes(length);
+ break;
+ }
}
positions.add(position);
@@ -533,13 +576,13 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
return positions;
}
- private void requestPhotoPacket(Channel channel, SocketAddress socketAddress, String imei, String file, int index) {
+ private void requestPhotoPacket(Channel channel, SocketAddress remoteAddress, String imei, String file, int index) {
if (channel != null) {
String content = "D00," + file + "," + index;
int length = 1 + imei.length() + 1 + content.length() + 5;
String response = String.format("@@O%02d,%s,%s*", length, imei, content);
response += Checksum.sum(response) + "\r\n";
- channel.writeAndFlush(new NetworkMessage(response, socketAddress));
+ channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
}
}
@@ -555,6 +598,13 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
String type = buf.toString(index + 1, 3, StandardCharsets.US_ASCII);
switch (type) {
+ case "AAC":
+ if (channel != null) {
+ String response = String.format("@@z27,%s,AAC,1*", imei);
+ response += Checksum.sum(response) + "\r\n";
+ channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
+ }
+ return null;
case "D00":
if (photo == null) {
photo = Unpooled.buffer();
@@ -579,7 +629,7 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
getLastLocation(position, null);
- position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(imei, photo, "jpg"));
+ position.set(Position.KEY_IMAGE, writeMediaFile(imei, photo, "jpg"));
photo.release();
photo = null;
@@ -594,6 +644,13 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
photo = Unpooled.buffer();
requestPhotoPacket(channel, remoteAddress, imei, "camera_picture.jpg", 0);
return null;
+ case "D82":
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(getDeviceSession(channel, remoteAddress, imei).getDeviceId());
+ getLastLocation(position, null);
+ String result = buf.toString(index + 1, buf.writerIndex() - index - 4, StandardCharsets.US_ASCII);
+ position.set(Position.KEY_RESULT, result);
+ return position;
case "CCC":
return decodeBinaryC(channel, remoteAddress, buf);
case "CCE":
diff --git a/src/main/java/org/traccar/protocol/MeitrackProtocolEncoder.java b/src/main/java/org/traccar/protocol/MeitrackProtocolEncoder.java
index 354e81434..365dbb35a 100644
--- a/src/main/java/org/traccar/protocol/MeitrackProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/MeitrackProtocolEncoder.java
@@ -15,11 +15,12 @@
*/
package org.traccar.protocol;
-import org.traccar.Context;
+import org.traccar.Protocol;
import org.traccar.StringProtocolEncoder;
+import org.traccar.config.Keys;
import org.traccar.helper.Checksum;
+import org.traccar.helper.model.AttributeUtil;
import org.traccar.model.Command;
-import org.traccar.Protocol;
import java.util.Map;
@@ -42,8 +43,8 @@ public class MeitrackProtocolEncoder extends StringProtocolEncoder {
Map<String, Object> attributes = command.getAttributes();
- boolean alternative = Context.getIdentityManager().lookupAttributeBoolean(
- command.getDeviceId(), getProtocolName() + ".alternative", false, false, true);
+ boolean alternative = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_ALTERNATIVE.withPrefix(getProtocolName()), command.getDeviceId());
switch (command.getType()) {
case Command.TYPE_POSITION_SINGLE:
diff --git a/src/main/java/org/traccar/protocol/MictrackProtocol.java b/src/main/java/org/traccar/protocol/MictrackProtocol.java
index 9fd9666e4..08bbe0c82 100644
--- a/src/main/java/org/traccar/protocol/MictrackProtocol.java
+++ b/src/main/java/org/traccar/protocol/MictrackProtocol.java
@@ -20,21 +20,25 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class MictrackProtocol extends BaseProtocol {
- public MictrackProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public MictrackProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new MictrackProtocolDecoder(MictrackProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new MictrackProtocolDecoder(MictrackProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java
index c72a742b9..84ba75e7c 100644
--- a/src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/MilesmateProtocol.java b/src/main/java/org/traccar/protocol/MilesmateProtocol.java
index 822711603..607dfc5bf 100644
--- a/src/main/java/org/traccar/protocol/MilesmateProtocol.java
+++ b/src/main/java/org/traccar/protocol/MilesmateProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class MilesmateProtocol extends BaseProtocol {
- public MilesmateProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public MilesmateProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/MilesmateProtocolDecoder.java b/src/main/java/org/traccar/protocol/MilesmateProtocolDecoder.java
index 901ceb8f7..21c629411 100644
--- a/src/main/java/org/traccar/protocol/MilesmateProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MilesmateProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/MiniFinderProtocol.java b/src/main/java/org/traccar/protocol/MiniFinderProtocol.java
index 0cc9598ed..1cb2a0007 100644
--- a/src/main/java/org/traccar/protocol/MiniFinderProtocol.java
+++ b/src/main/java/org/traccar/protocol/MiniFinderProtocol.java
@@ -21,11 +21,15 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class MiniFinderProtocol extends BaseProtocol {
- public MiniFinderProtocol() {
+ @Inject
+ public MiniFinderProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_SET_TIMEZONE,
Command.TYPE_VOICE_MONITORING,
@@ -38,9 +42,9 @@ public class MiniFinderProtocol extends BaseProtocol {
Command.TYPE_MODE_DEEP_SLEEP,
Command.TYPE_SOS_NUMBER,
Command.TYPE_SET_INDICATOR);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ";\0", ";"));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java b/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java
index d5be31cec..1fdb1ece0 100644
--- a/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.Parser;
@@ -143,7 +143,7 @@ public class MiniFinderProtocolDecoder extends BaseProtocolDecoder {
}
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
- if (deviceSession == null || !sentence.matches("![35A-D],.*")) {
+ if (deviceSession == null || !sentence.matches("![345A-D],.*")) {
return null;
}
@@ -161,6 +161,20 @@ public class MiniFinderProtocolDecoder extends BaseProtocolDecoder {
return position;
+ } else if (type.equals("4")) {
+
+ String[] values = sentence.split(",");
+
+ getLastLocation(position, null);
+
+ for (int i = 1; i <= 3; i++) {
+ if (!values[i + 1].isEmpty()) {
+ position.set("phone" + i, values[i + 1]);
+ }
+ }
+
+ return position;
+
} else if (type.equals("5")) {
String[] values = sentence.split(",");
diff --git a/src/main/java/org/traccar/protocol/Minifinder2Protocol.java b/src/main/java/org/traccar/protocol/Minifinder2Protocol.java
index f8801db74..c12933b81 100644
--- a/src/main/java/org/traccar/protocol/Minifinder2Protocol.java
+++ b/src/main/java/org/traccar/protocol/Minifinder2Protocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2019 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,16 +19,24 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+import org.traccar.model.Command;
import java.nio.ByteOrder;
+import jakarta.inject.Inject;
+
public class Minifinder2Protocol extends BaseProtocol {
- public Minifinder2Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Minifinder2Protocol(Config config) {
+ setSupportedDataCommands(
+ Command.TYPE_FIRMWARE_UPDATE);
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
- pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1200, 2, 2, 4, 0, true));
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 2048, 2, 2, 4, 0, true));
+ pipeline.addLast(new Minifinder2ProtocolEncoder(Minifinder2Protocol.this));
pipeline.addLast(new Minifinder2ProtocolDecoder(Minifinder2Protocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
index 641a45864..6289bd2eb 100644
--- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2019 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -48,9 +48,11 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_DATA = 0x01;
public static final int MSG_CONFIGURATION = 0x02;
public static final int MSG_SERVICES = 0x03;
+ public static final int MSG_SYSTEM_CONTROL = 0x04;
+ public static final int MSG_FIRMWARE = 0x7E;
public static final int MSG_RESPONSE = 0x7F;
- private String decodeAlarm(int code) {
+ private String decodeAlarm(long code) {
if (BitUtil.check(code, 0)) {
return Position.ALARM_LOW_BATTERY;
}
@@ -146,10 +148,10 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
int type = buf.readUnsignedByte();
if (BitUtil.check(flags, 4)) {
- sendResponse(channel, remoteAddress, index, type, buf);
+ sendResponse(channel, remoteAddress, index, type, buf.slice());
}
- if (type == MSG_DATA) {
+ if (type == MSG_DATA || type == MSG_SERVICES) {
List<Position> positions = new LinkedList<>();
Set<Integer> keys = new HashSet<>();
@@ -177,11 +179,16 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
case 0x01:
deviceSession = getDeviceSession(
channel, remoteAddress, buf.readCharSequence(15, StandardCharsets.US_ASCII).toString());
-
- position.setDeviceId(deviceSession.getDeviceId());
+ if (deviceSession == null) {
+ return null;
+ }
break;
case 0x02:
- position.set(Position.KEY_ALARM, decodeAlarm(buf.readIntLE()));
+ long alarm = buf.readUnsignedIntLE();
+ position.set(Position.KEY_ALARM, decodeAlarm(alarm));
+ if (BitUtil.check(alarm, 31)) {
+ position.set("bark", true);
+ }
break;
case 0x14:
position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
@@ -194,7 +201,9 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE()));
position.setCourse(buf.readUnsignedShortLE());
position.setAltitude(buf.readShortLE());
- position.setValid(buf.readUnsignedShortLE() > 0);
+ int hdop = buf.readUnsignedShortLE();
+ position.setValid(hdop > 0);
+ position.set(Position.KEY_HDOP, hdop * 0.1);
position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE());
position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
break;
@@ -231,6 +240,14 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
case 0x24:
position.setTime(new Date(buf.readUnsignedIntLE() * 1000));
long status = buf.readUnsignedIntLE();
+ if (BitUtil.check(status, 4)) {
+ position.set(Position.KEY_CHARGE, true);
+ }
+ if (BitUtil.check(status, 7)) {
+ position.set(Position.KEY_ARCHIVE, true);
+ }
+ position.set(Position.KEY_MOTION, BitUtil.check(status, 9));
+ position.set(Position.KEY_RSSI, BitUtil.between(status, 19, 24));
position.set(Position.KEY_BATTERY_LEVEL, BitUtil.from(status, 24));
position.set(Position.KEY_STATUS, status);
break;
@@ -260,8 +277,24 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
hasLocation = true;
break;
case 0x30:
- buf.readUnsignedInt(); // timestamp
- position.set(Position.KEY_STEPS, buf.readUnsignedInt());
+ buf.readUnsignedIntLE(); // timestamp
+ position.set(Position.KEY_STEPS, buf.readUnsignedIntLE());
+ break;
+ case 0x31:
+ int i = 1;
+ while (buf.readerIndex() < endIndex) {
+ position.set("activity" + i + "Time", buf.readUnsignedIntLE());
+ position.set("activity" + i, buf.readUnsignedIntLE());
+ i += 1;
+ }
+ break;
+ case 0x37:
+ buf.readUnsignedIntLE(); // timestamp
+ long barking = buf.readUnsignedIntLE();
+ if (BitUtil.check(barking, 31)) {
+ position.set("barkStop", true);
+ }
+ position.set("barkCount", BitUtil.to(barking, 31));
break;
case 0x40:
buf.readUnsignedIntLE(); // timestamp
@@ -291,6 +324,23 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
return positions;
+ } else if (type == MSG_RESPONSE) {
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ getLastLocation(position, null);
+
+ buf.readUnsignedByte(); // length
+ position.set(Position.KEY_RESULT, String.valueOf(buf.readUnsignedByte()));
+
+ return position;
+
}
return null;
diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java
new file mode 100644
index 000000000..fab3c3a6d
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolEncoder.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import org.traccar.BaseProtocolEncoder;
+import org.traccar.Protocol;
+import org.traccar.helper.Checksum;
+import org.traccar.model.Command;
+import org.traccar.model.Device;
+
+import java.nio.charset.StandardCharsets;
+
+public class Minifinder2ProtocolEncoder extends BaseProtocolEncoder {
+
+ public Minifinder2ProtocolEncoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private ByteBuf encodeContent(ByteBuf content) {
+
+ ByteBuf buf = Unpooled.buffer();
+
+ buf.writeByte(0xAB); // header
+ buf.writeByte(0x00); // properties
+ buf.writeShortLE(content.readableBytes());
+ buf.writeShortLE(Checksum.crc16(Checksum.CRC16_XMODEM, content.nioBuffer()));
+ buf.writeShortLE(1); // index
+ buf.writeBytes(content);
+
+ return buf;
+ }
+
+ @Override
+ protected Object encodeCommand(Command command) {
+
+ Device device = getCacheManager().getObject(Device.class, command.getDeviceId());
+ if ("Nano".equalsIgnoreCase(device.getModel())) {
+ ByteBuf content = Unpooled.buffer();
+ if (command.getType().equals(Command.TYPE_FIRMWARE_UPDATE)) {
+ String url = command.getString(Command.KEY_DATA);
+ content.writeByte(Minifinder2ProtocolDecoder.MSG_SYSTEM_CONTROL);
+ content.writeByte(1 + url.length());
+ content.writeByte(0x30); // type
+ content.writeCharSequence(url, StandardCharsets.US_ASCII);
+ return encodeContent(content);
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/MobilogixProtocol.java b/src/main/java/org/traccar/protocol/MobilogixProtocol.java
index 28380a2af..36d6b5ed2 100644
--- a/src/main/java/org/traccar/protocol/MobilogixProtocol.java
+++ b/src/main/java/org/traccar/protocol/MobilogixProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class MobilogixProtocol extends BaseProtocol {
- public MobilogixProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public MobilogixProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ']'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/MobilogixProtocolDecoder.java b/src/main/java/org/traccar/protocol/MobilogixProtocolDecoder.java
index 86c89e336..d7600ecbb 100644
--- a/src/main/java/org/traccar/protocol/MobilogixProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MobilogixProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/MoovboxProtocol.java b/src/main/java/org/traccar/protocol/MoovboxProtocol.java
index 7b554266f..af853fe67 100644
--- a/src/main/java/org/traccar/protocol/MoovboxProtocol.java
+++ b/src/main/java/org/traccar/protocol/MoovboxProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class MoovboxProtocol extends BaseProtocol {
- public MoovboxProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public MoovboxProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(65535));
diff --git a/src/main/java/org/traccar/protocol/MoovboxProtocolDecoder.java b/src/main/java/org/traccar/protocol/MoovboxProtocolDecoder.java
index 3116d073c..8e6679b05 100644
--- a/src/main/java/org/traccar/protocol/MoovboxProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MoovboxProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.model.Position;
import org.w3c.dom.Document;
diff --git a/src/main/java/org/traccar/protocol/MotorProtocol.java b/src/main/java/org/traccar/protocol/MotorProtocol.java
index 680687e15..f17886577 100644
--- a/src/main/java/org/traccar/protocol/MotorProtocol.java
+++ b/src/main/java/org/traccar/protocol/MotorProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class MotorProtocol extends BaseProtocol {
- public MotorProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public MotorProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new MotorProtocolDecoder(MotorProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/MotorProtocolDecoder.java b/src/main/java/org/traccar/protocol/MotorProtocolDecoder.java
index 8ce4fe8b1..9bca4d9bc 100644
--- a/src/main/java/org/traccar/protocol/MotorProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MotorProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BcdUtil;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/Mta6Protocol.java b/src/main/java/org/traccar/protocol/Mta6Protocol.java
index 14a66ce5c..c1c6eb829 100644
--- a/src/main/java/org/traccar/protocol/Mta6Protocol.java
+++ b/src/main/java/org/traccar/protocol/Mta6Protocol.java
@@ -19,22 +19,25 @@ import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
-import org.traccar.Context;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
+import jakarta.inject.Inject;
+
public class Mta6Protocol extends BaseProtocol {
- public Mta6Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Mta6Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(65535));
pipeline.addLast(new Mta6ProtocolDecoder(
- Mta6Protocol.this, !Context.getConfig().getBoolean(Keys.PROTOCOL_CAN.withPrefix(getName()))));
+ Mta6Protocol.this, !config.getBoolean(Keys.PROTOCOL_CAN.withPrefix(getName()))));
}
});
}
diff --git a/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java
index 88419b871..896c7a2d2 100644
--- a/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Mta6ProtocolDecoder.java
@@ -26,7 +26,7 @@ import io.netty.handler.codec.http.HttpVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/MtxProtocol.java b/src/main/java/org/traccar/protocol/MtxProtocol.java
index 44372ce83..12d324019 100644
--- a/src/main/java/org/traccar/protocol/MtxProtocol.java
+++ b/src/main/java/org/traccar/protocol/MtxProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class MtxProtocol extends BaseProtocol {
- public MtxProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public MtxProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/MtxProtocolDecoder.java b/src/main/java/org/traccar/protocol/MtxProtocolDecoder.java
index d1207bedf..e94d12b36 100644
--- a/src/main/java/org/traccar/protocol/MtxProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MtxProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/MxtProtocol.java b/src/main/java/org/traccar/protocol/MxtProtocol.java
index dbe43fe45..2f0cc1658 100644
--- a/src/main/java/org/traccar/protocol/MxtProtocol.java
+++ b/src/main/java/org/traccar/protocol/MxtProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class MxtProtocol extends BaseProtocol {
- public MxtProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public MxtProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new MxtFrameDecoder());
pipeline.addLast(new MxtProtocolDecoder(MxtProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/MxtProtocolDecoder.java b/src/main/java/org/traccar/protocol/MxtProtocolDecoder.java
index 379b610e1..b3e2295e8 100644
--- a/src/main/java/org/traccar/protocol/MxtProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MxtProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/NavigilProtocol.java b/src/main/java/org/traccar/protocol/NavigilProtocol.java
index 2c946c39f..a309235c5 100644
--- a/src/main/java/org/traccar/protocol/NavigilProtocol.java
+++ b/src/main/java/org/traccar/protocol/NavigilProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class NavigilProtocol extends BaseProtocol {
- public NavigilProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public NavigilProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new NavigilFrameDecoder());
pipeline.addLast(new NavigilProtocolDecoder(NavigilProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/NavigilProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavigilProtocolDecoder.java
index db5521201..6dadbc559 100644
--- a/src/main/java/org/traccar/protocol/NavigilProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/NavigilProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Checksum;
diff --git a/src/main/java/org/traccar/protocol/NavisProtocol.java b/src/main/java/org/traccar/protocol/NavisProtocol.java
index d5af6838d..96b5b0de0 100644
--- a/src/main/java/org/traccar/protocol/NavisProtocol.java
+++ b/src/main/java/org/traccar/protocol/NavisProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class NavisProtocol extends BaseProtocol {
- public NavisProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public NavisProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new NavisFrameDecoder());
pipeline.addLast(new NavisProtocolDecoder(NavisProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/NavisProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavisProtocolDecoder.java
index 7ba474ae0..77158b315 100644
--- a/src/main/java/org/traccar/protocol/NavisProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/NavisProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,12 +19,11 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.Checksum;
-import org.traccar.helper.Checksum.Algorithm;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
@@ -591,10 +590,8 @@ public class NavisProtocolDecoder extends BaseProtocolDecoder {
private void sendFlexReply(Channel channel, ByteBuf data) {
if (channel != null) {
- ByteBuf cs = Unpooled.buffer(1);
- cs.writeByte(Checksum.crc8(new Algorithm(8, 0x31, 0xFF, false, false, 0x00), data.nioBuffer()));
-
- channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(data, cs), channel.remoteAddress()));
+ data.writeByte(Checksum.crc8(Checksum.CRC8_EGTS, data.nioBuffer()));
+ channel.writeAndFlush(new NetworkMessage(data, channel.remoteAddress()));
}
}
diff --git a/src/main/java/org/traccar/protocol/NavisetProtocol.java b/src/main/java/org/traccar/protocol/NavisetProtocol.java
index 78755ea4d..6df0b0436 100644
--- a/src/main/java/org/traccar/protocol/NavisetProtocol.java
+++ b/src/main/java/org/traccar/protocol/NavisetProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class NavisetProtocol extends BaseProtocol {
- public NavisetProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public NavisetProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new NavisetFrameDecoder());
pipeline.addLast(new NavisetProtocolDecoder(NavisetProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/NavisetProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavisetProtocolDecoder.java
index 10d71d76c..47d10b310 100644
--- a/src/main/java/org/traccar/protocol/NavisetProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/NavisetProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocol.java b/src/main/java/org/traccar/protocol/NavtelecomProtocol.java
index 29ce8c41e..de5f93df1 100644
--- a/src/main/java/org/traccar/protocol/NavtelecomProtocol.java
+++ b/src/main/java/org/traccar/protocol/NavtelecomProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class NavtelecomProtocol extends BaseProtocol {
- public NavtelecomProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public NavtelecomProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new NavtelecomFrameDecoder());
pipeline.addLast(new NavtelecomProtocolDecoder(NavtelecomProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java
index ecaa6cbf4..87cccbeaa 100644
--- a/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2021 - 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.
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -196,7 +196,7 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder {
for (int j = 0; j < bits.length(); j++) {
if (bits.get(j)) {
- int value = 0;
+ int value;
switch (j + 1) {
case 1:
@@ -278,11 +278,11 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder {
case 42:
case 43:
value = buf.readUnsignedShortLE();
- position.set("rs485Fuel" + (j + 2 - 38), (value < 65500) ? value : null);
+ position.set("fuel" + (j + 2 - 38), (value < 65500) ? value : null);
break;
case 44:
value = buf.readUnsignedShortLE();
- position.set("rs232Fuel", (value < 65500) ? value : null);
+ position.set(Position.KEY_FUEL_LEVEL, (value < 65500) ? value : null);
break;
case 45:
case 46:
@@ -293,7 +293,17 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder {
case 51:
case 52:
value = buf.readByte();
- position.set(Position.PREFIX_TEMP + (j + 2 - 45), (value != 0x80) ? value : null);
+ position.set(
+ Position.PREFIX_TEMP + (j + 2 - 45),
+ (value != (byte) 0x80) ? value : null);
+ break;
+ case 78:
+ case 79:
+ case 80:
+ case 81:
+ case 82:
+ case 83:
+ position.set("fuelTemp" + (j + 2 - 78), (int) buf.readByte());
break;
case 53:
value = buf.readUnsignedShortLE();
diff --git a/src/main/java/org/traccar/protocol/NdtpV6Protocol.java b/src/main/java/org/traccar/protocol/NdtpV6Protocol.java
new file mode 100644
index 000000000..9493132f5
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/NdtpV6Protocol.java
@@ -0,0 +1,39 @@
+/*
+ * 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.protocol;
+
+import io.netty.handler.codec.string.StringEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
+
+public class NdtpV6Protocol extends BaseProtocol {
+
+ @Inject
+ public NdtpV6Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new StringEncoder());
+ pipeline.addLast(new NdtpV6ProtocolDecoder(NdtpV6Protocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/NdtpV6ProtocolDecoder.java b/src/main/java/org/traccar/protocol/NdtpV6ProtocolDecoder.java
new file mode 100644
index 000000000..35cb0bae8
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/NdtpV6ProtocolDecoder.java
@@ -0,0 +1,203 @@
+/*
+ * 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.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.NetworkMessage;
+import org.traccar.Protocol;
+import org.traccar.helper.BitUtil;
+import org.traccar.helper.Checksum;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+import org.traccar.session.DeviceSession;
+
+import java.net.SocketAddress;
+import java.util.Date;
+
+public class NdtpV6ProtocolDecoder extends BaseProtocolDecoder {
+
+ public NdtpV6ProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private static final byte[] SIGNATURE = {0x7E, 0x7E};
+
+ private static final int NPL_FLAG_CRC = 2;
+ private static final int NPH_RESULT_OK = 0x00000000;
+ private static final int NPL_TYPE_NPH = 2;
+ private static final int NPL_ADDRESS_SERVER = 0;
+
+ private static final int NPH_RESULT = 0;
+
+ private static final int NPH_SRV_GENERIC_CONTROLS = 0;
+ private static final int NPH_SRV_NAVDATA = 1;
+
+ private static final int NPH_SGC_RESULT = NPH_RESULT;
+ private static final int NPH_SGC_CONN_REQUEST = 100;
+
+ private static final int NPH_SND_RESULT = NPH_RESULT;
+
+ private void sendResponse(
+ Channel channel, int serviceId, long requestId) {
+
+ ByteBuf content = Unpooled.buffer();
+ content.writeShortLE(serviceId);
+ content.writeIntLE(NPH_SND_RESULT);
+ content.writeIntLE((int) requestId);
+ content.writeIntLE(NPH_RESULT_OK);
+
+ ByteBuf response = Unpooled.buffer();
+ response.writeBytes(SIGNATURE);
+ response.writeShortLE(content.readableBytes());
+ response.writeShortLE(NPL_FLAG_CRC); // flags
+ response.writeShort(Checksum.crc16(Checksum.CRC16_MODBUS, content.nioBuffer()));
+ response.writeByte(NPL_TYPE_NPH); // type
+ response.writeIntLE(NPL_ADDRESS_SERVER); // peer address
+ response.writeShortLE(0); // request id
+ response.writeBytes(content);
+ content.release();
+
+ channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress()));
+ }
+
+ private static final short MAIN_NAV_DATA = 0;
+ private static final short ADDITIONAL_NAV_DATA = 2;
+
+ private void decodeData(ByteBuf buf, Position position) {
+
+ short itemType;
+ short itemIndex;
+
+ itemType = buf.readUnsignedByte();
+ itemIndex = buf.readUnsignedByte();
+ if (itemType == MAIN_NAV_DATA && (itemIndex == 0 || itemIndex == 1)) {
+
+ position.setTime(new Date(buf.readUnsignedIntLE() * 1000));
+ position.setLongitude(buf.readIntLE() / 10000000.0);
+ position.setLatitude(buf.readIntLE() / 10000000.0);
+
+ short flags = buf.readUnsignedByte();
+ position.setValid(BitUtil.check(flags, 7));
+ if (BitUtil.check(flags, 1)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
+ }
+
+ position.set(Position.KEY_BATTERY, buf.readUnsignedByte() * 20);
+ position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShortLE());
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE()));
+ position.setCourse(buf.readUnsignedShortLE());
+
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedShortLE());
+ position.setAltitude(buf.readShortLE());
+ position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
+ position.set(Position.KEY_PDOP, buf.readUnsignedByte());
+ }
+
+ itemType = buf.readUnsignedByte();
+ itemIndex = buf.readUnsignedByte();
+ if (itemType == ADDITIONAL_NAV_DATA && itemIndex == 0) {
+
+ position.set(Position.KEY_BATTERY_LEVEL, Math.max((buf.readUnsignedShortLE() - 3600) / 6, 100));
+ position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShortLE());
+ position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShortLE());
+ position.set(Position.PREFIX_ADC + 4, buf.readUnsignedShortLE());
+
+ buf.readUnsignedByte(); // inputs
+ buf.readUnsignedByte(); // outputs
+ buf.readUnsignedShortLE(); // in1 count
+ buf.readUnsignedShortLE(); // in2 count
+ buf.readUnsignedShortLE(); // in3 count
+ buf.readUnsignedShortLE(); // in4 count
+ buf.readUnsignedIntLE(); // track length
+
+ position.set(Position.KEY_ANTENNA, buf.readUnsignedByte());
+ position.set(Position.KEY_GPS, buf.readUnsignedByte());
+ position.set(Position.KEY_ACCELERATION, buf.readUnsignedByte());
+ position.set(Position.KEY_POWER, buf.readUnsignedByte() * 200);
+ }
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ByteBuf buf = (ByteBuf) msg;
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
+
+ buf.skipBytes(2); // signature
+ buf.readUnsignedShortLE(); // length
+ buf.readUnsignedShortLE(); // connection flags
+ buf.readUnsignedShortLE(); // checksum
+ buf.readUnsignedByte(); // type
+ buf.readUnsignedIntLE(); // address
+ buf.readUnsignedShortLE(); // identification
+
+ int serviceId = buf.readUnsignedShortLE();
+ int serviceType = buf.readUnsignedShortLE();
+ buf.readUnsignedShortLE(); // request flags
+ long requestId = buf.readUnsignedIntLE();
+
+ if (deviceSession == null && serviceId == NPH_SRV_GENERIC_CONTROLS && serviceType == NPH_SGC_CONN_REQUEST) {
+
+ buf.readUnsignedShortLE(); // version major
+ buf.readUnsignedShortLE(); // version minor
+ buf.readUnsignedShortLE(); // connection flags
+
+ int deviceId = buf.readUnsignedShortLE();
+ Position position = new Position(getProtocolName());
+ deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(deviceId));
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ if (channel != null) {
+ sendResponse(channel, serviceId, requestId);
+ }
+
+ position.set(Position.KEY_RESULT, String.valueOf(NPH_SGC_RESULT));
+ position.setTime(new Date());
+ getLastLocation(position, new Date());
+ position.setValid(false);
+
+ return position;
+
+ }
+
+ if (serviceId == NPH_SRV_NAVDATA) {
+
+ deviceSession = getDeviceSession(channel, remoteAddress);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ if (channel != null) {
+ sendResponse(channel, serviceId, requestId);
+ }
+
+ decodeData(buf, position);
+
+ return position;
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/NdtpV6ProtocolEncoder.java b/src/main/java/org/traccar/protocol/NdtpV6ProtocolEncoder.java
new file mode 100644
index 000000000..7aac8658a
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/NdtpV6ProtocolEncoder.java
@@ -0,0 +1,42 @@
+/*
+ * 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.protocol;
+
+import org.traccar.BaseProtocolEncoder;
+import org.traccar.Protocol;
+import org.traccar.model.Command;
+
+public class NdtpV6ProtocolEncoder extends BaseProtocolEncoder {
+
+ public NdtpV6ProtocolEncoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object encodeCommand(Command command) {
+ switch (command.getType()) {
+ case Command.TYPE_IDENTIFICATION:
+ return "BB+IDNT";
+ case Command.TYPE_REBOOT_DEVICE:
+ return "BB+RESET";
+ case Command.TYPE_POSITION_SINGLE:
+ return "BB+RRCD";
+ default:
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/NeosProtocol.java b/src/main/java/org/traccar/protocol/NeosProtocol.java
index e545a9969..16a6ba5a0 100644
--- a/src/main/java/org/traccar/protocol/NeosProtocol.java
+++ b/src/main/java/org/traccar/protocol/NeosProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class NeosProtocol extends BaseProtocol {
- public NeosProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public NeosProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new NeosProtocolDecoder(NeosProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/NeosProtocolDecoder.java b/src/main/java/org/traccar/protocol/NeosProtocolDecoder.java
index 6b5596dba..18ebc49da 100644
--- a/src/main/java/org/traccar/protocol/NeosProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/NeosProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/NetProtocol.java b/src/main/java/org/traccar/protocol/NetProtocol.java
index c114d19fc..e011660da 100644
--- a/src/main/java/org/traccar/protocol/NetProtocol.java
+++ b/src/main/java/org/traccar/protocol/NetProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class NetProtocol extends BaseProtocol {
- public NetProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public NetProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '!'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/NetProtocolDecoder.java b/src/main/java/org/traccar/protocol/NetProtocolDecoder.java
index c71a792a2..ebffb06f1 100644
--- a/src/main/java/org/traccar/protocol/NetProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/NetProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/NiotProtocol.java b/src/main/java/org/traccar/protocol/NiotProtocol.java
index b57b18a3a..7eacd5ff3 100644
--- a/src/main/java/org/traccar/protocol/NiotProtocol.java
+++ b/src/main/java/org/traccar/protocol/NiotProtocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class NiotProtocol extends BaseProtocol {
- public NiotProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public NiotProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2));
pipeline.addLast(new NiotProtocolDecoder(NiotProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/NiotProtocolDecoder.java b/src/main/java/org/traccar/protocol/NiotProtocolDecoder.java
index 47c6e2ffd..35614ccca 100644
--- a/src/main/java/org/traccar/protocol/NiotProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/NiotProtocolDecoder.java
@@ -20,7 +20,8 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.helper.BufferUtil;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BcdUtil;
@@ -57,12 +58,6 @@ public class NiotProtocolDecoder extends BaseProtocolDecoder {
}
}
- private double readCoordinate(ByteBuf buf) {
- long value = buf.readUnsignedInt();
- double result = BitUtil.to(value, 31) / 1800000.0;
- return BitUtil.check(value, 31) ? -result : result;
- }
-
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -96,8 +91,8 @@ public class NiotProtocolDecoder extends BaseProtocolDecoder {
.setSecond(BcdUtil.readInteger(buf, 2));
position.setTime(dateBuilder.getDate());
- position.setLatitude(readCoordinate(buf));
- position.setLongitude(readCoordinate(buf));
+ position.setLatitude(BufferUtil.readSignedMagnitudeInt(buf) / 1800000.0);
+ position.setLongitude(BufferUtil.readSignedMagnitudeInt(buf) / 1800000.0);
BcdUtil.readInteger(buf, 4); // reserved
position.setCourse(BcdUtil.readInteger(buf, 4));
diff --git a/src/main/java/org/traccar/protocol/NoranProtocol.java b/src/main/java/org/traccar/protocol/NoranProtocol.java
index 3df364c30..d03e52be5 100644
--- a/src/main/java/org/traccar/protocol/NoranProtocol.java
+++ b/src/main/java/org/traccar/protocol/NoranProtocol.java
@@ -18,20 +18,24 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class NoranProtocol extends BaseProtocol {
- public NoranProtocol() {
+ @Inject
+ public NoranProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_POSITION_SINGLE,
Command.TYPE_POSITION_PERIODIC,
Command.TYPE_POSITION_STOP,
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME);
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new NoranProtocolEncoder(NoranProtocol.this));
pipeline.addLast(new NoranProtocolDecoder(NoranProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/NoranProtocolDecoder.java b/src/main/java/org/traccar/protocol/NoranProtocolDecoder.java
index 53dae7fd6..53b58f9b6 100644
--- a/src/main/java/org/traccar/protocol/NoranProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/NoranProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/NvsProtocol.java b/src/main/java/org/traccar/protocol/NvsProtocol.java
index d319b22f3..8a4ece30d 100644
--- a/src/main/java/org/traccar/protocol/NvsProtocol.java
+++ b/src/main/java/org/traccar/protocol/NvsProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class NvsProtocol extends BaseProtocol {
- public NvsProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public NvsProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new NvsFrameDecoder());
pipeline.addLast(new NvsProtocolDecoder(NvsProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/NvsProtocolDecoder.java b/src/main/java/org/traccar/protocol/NvsProtocolDecoder.java
index 5d1159f7d..f826c4121 100644
--- a/src/main/java/org/traccar/protocol/NvsProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/NvsProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.UnitsConverter;
diff --git a/src/main/java/org/traccar/protocol/NyitechProtocol.java b/src/main/java/org/traccar/protocol/NyitechProtocol.java
index 58974be5c..225b1bd5a 100644
--- a/src/main/java/org/traccar/protocol/NyitechProtocol.java
+++ b/src/main/java/org/traccar/protocol/NyitechProtocol.java
@@ -19,15 +19,19 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import java.nio.ByteOrder;
+import jakarta.inject.Inject;
+
public class NyitechProtocol extends BaseProtocol {
- public NyitechProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public NyitechProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, -4, 0, true));
pipeline.addLast(new NyitechProtocolDecoder(NyitechProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/NyitechProtocolDecoder.java b/src/main/java/org/traccar/protocol/NyitechProtocolDecoder.java
index 62b41a2ea..49bc5b824 100644
--- a/src/main/java/org/traccar/protocol/NyitechProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/NyitechProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/ObdDongleProtocol.java b/src/main/java/org/traccar/protocol/ObdDongleProtocol.java
index 10a55759b..9fcc35d0d 100644
--- a/src/main/java/org/traccar/protocol/ObdDongleProtocol.java
+++ b/src/main/java/org/traccar/protocol/ObdDongleProtocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class ObdDongleProtocol extends BaseProtocol {
- public ObdDongleProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public ObdDongleProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1099, 20, 2, 3, 0));
pipeline.addLast(new ObdDongleProtocolDecoder(ObdDongleProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/ObdDongleProtocolDecoder.java b/src/main/java/org/traccar/protocol/ObdDongleProtocolDecoder.java
index 1c9771ce9..bf0ba6f82 100644
--- a/src/main/java/org/traccar/protocol/ObdDongleProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ObdDongleProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/OigoProtocol.java b/src/main/java/org/traccar/protocol/OigoProtocol.java
index 5056f68aa..3483f8270 100644
--- a/src/main/java/org/traccar/protocol/OigoProtocol.java
+++ b/src/main/java/org/traccar/protocol/OigoProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class OigoProtocol extends BaseProtocol {
- public OigoProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public OigoProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new OigoProtocolDecoder(OigoProtocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/OigoProtocolDecoder.java b/src/main/java/org/traccar/protocol/OigoProtocolDecoder.java
index b9cc71e8c..b0c7c3bc6 100644
--- a/src/main/java/org/traccar/protocol/OigoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/OigoProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/OkoProtocol.java b/src/main/java/org/traccar/protocol/OkoProtocol.java
index 9571ccc48..6ca6c0e93 100644
--- a/src/main/java/org/traccar/protocol/OkoProtocol.java
+++ b/src/main/java/org/traccar/protocol/OkoProtocol.java
@@ -20,13 +20,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class OkoProtocol extends BaseProtocol {
- public OkoProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public OkoProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '}'));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new OkoProtocolDecoder(OkoProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/OkoProtocolDecoder.java b/src/main/java/org/traccar/protocol/OkoProtocolDecoder.java
index fa35ab455..3bb62acb9 100644
--- a/src/main/java/org/traccar/protocol/OkoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/OkoProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/OmnicommProtocol.java b/src/main/java/org/traccar/protocol/OmnicommProtocol.java
index 96660cb59..b59b84132 100644
--- a/src/main/java/org/traccar/protocol/OmnicommProtocol.java
+++ b/src/main/java/org/traccar/protocol/OmnicommProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class OmnicommProtocol extends BaseProtocol {
- public OmnicommProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public OmnicommProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new OmnicommFrameDecoder());
pipeline.addLast(new OmnicommProtocolDecoder(OmnicommProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/OmnicommProtocolDecoder.java b/src/main/java/org/traccar/protocol/OmnicommProtocolDecoder.java
index f90d1f2b3..9d747032b 100644
--- a/src/main/java/org/traccar/protocol/OmnicommProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/OmnicommProtocolDecoder.java
@@ -21,7 +21,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/OpenGtsProtocol.java b/src/main/java/org/traccar/protocol/OpenGtsProtocol.java
index 5ef3260c6..24d6de706 100644
--- a/src/main/java/org/traccar/protocol/OpenGtsProtocol.java
+++ b/src/main/java/org/traccar/protocol/OpenGtsProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class OpenGtsProtocol extends BaseProtocol {
- public OpenGtsProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public OpenGtsProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(16384));
diff --git a/src/main/java/org/traccar/protocol/OpenGtsProtocolDecoder.java b/src/main/java/org/traccar/protocol/OpenGtsProtocolDecoder.java
index b76cbfa85..255a81ae6 100644
--- a/src/main/java/org/traccar/protocol/OpenGtsProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/OpenGtsProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.QueryStringDecoder;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/OrbcommProtocol.java b/src/main/java/org/traccar/protocol/OrbcommProtocol.java
index bdfce3b1e..06b00619c 100644
--- a/src/main/java/org/traccar/protocol/OrbcommProtocol.java
+++ b/src/main/java/org/traccar/protocol/OrbcommProtocol.java
@@ -21,18 +21,22 @@ import io.netty.handler.codec.http.HttpResponseDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerClient;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class OrbcommProtocol extends BaseProtocol {
- public OrbcommProtocol() {
- addClient(new TrackerClient(getName()) {
+ @Inject
+ public OrbcommProtocol(Config config) {
+ addClient(new TrackerClient(config, getName()) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpRequestEncoder());
pipeline.addLast(new HttpResponseDecoder());
pipeline.addLast(new HttpObjectAggregator(65535));
pipeline.addLast(new OrbcommProtocolDecoder(OrbcommProtocol.this));
- pipeline.addLast(new OrbcommProtocolPoller(OrbcommProtocol.this));
+ pipeline.addLast(new OrbcommProtocolPoller(OrbcommProtocol.this, config));
}
});
}
diff --git a/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java b/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java
index 7277b1e5f..7ed13d647 100644
--- a/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java
@@ -19,15 +19,15 @@ import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpResponse;
import org.traccar.BasePipelineFactory;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
-import javax.json.Json;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
-import javax.json.JsonValue;
+import jakarta.json.Json;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonValue;
import java.io.StringReader;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
@@ -70,8 +70,7 @@ public class OrbcommProtocolDecoder extends BaseProtocolDecoder {
JsonArray messages = json.getJsonArray("Messages");
for (int i = 0; i < messages.size(); i++) {
JsonObject message = messages.getJsonObject(i);
- DeviceSession deviceSession = getDeviceSession(
- channel, remoteAddress, true, message.getString("MobileID"));
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, message.getString("MobileID"));
if (deviceSession != null) {
Position position = new Position(getProtocolName());
diff --git a/src/main/java/org/traccar/protocol/OrbcommProtocolPoller.java b/src/main/java/org/traccar/protocol/OrbcommProtocolPoller.java
index 6a2d7a92d..0f57bfb49 100644
--- a/src/main/java/org/traccar/protocol/OrbcommProtocolPoller.java
+++ b/src/main/java/org/traccar/protocol/OrbcommProtocolPoller.java
@@ -24,8 +24,8 @@ import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.QueryStringEncoder;
import org.traccar.BaseProtocolPoller;
-import org.traccar.Context;
import org.traccar.Protocol;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import java.net.SocketAddress;
@@ -46,11 +46,11 @@ public class OrbcommProtocolPoller extends BaseProtocolPoller {
this.startTime = startTime;
}
- public OrbcommProtocolPoller(Protocol protocol) {
- super(Context.getConfig().getLong(Keys.PROTOCOL_INTERVAL.withPrefix(protocol.getName())));
- accessId = Context.getConfig().getString(Keys.ORBCOMM_ACCESS_ID);
- password = Context.getConfig().getString(Keys.ORBCOMM_PASSWORD);
- host = Context.getConfig().getString(Keys.PROTOCOL_ADDRESS.withPrefix(protocol.getName()));
+ public OrbcommProtocolPoller(Protocol protocol, Config config) {
+ super(config.getLong(Keys.PROTOCOL_INTERVAL.withPrefix(protocol.getName())));
+ accessId = config.getString(Keys.ORBCOMM_ACCESS_ID);
+ password = config.getString(Keys.ORBCOMM_PASSWORD);
+ host = config.getString(Keys.PROTOCOL_ADDRESS.withPrefix(protocol.getName()));
}
@Override
diff --git a/src/main/java/org/traccar/protocol/OrionProtocol.java b/src/main/java/org/traccar/protocol/OrionProtocol.java
index 8485ae638..b78af462b 100644
--- a/src/main/java/org/traccar/protocol/OrionProtocol.java
+++ b/src/main/java/org/traccar/protocol/OrionProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class OrionProtocol extends BaseProtocol {
- public OrionProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public OrionProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new OrionFrameDecoder());
pipeline.addLast(new OrionProtocolDecoder(OrionProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/OrionProtocolDecoder.java b/src/main/java/org/traccar/protocol/OrionProtocolDecoder.java
index af819989e..681891edb 100644
--- a/src/main/java/org/traccar/protocol/OrionProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/OrionProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/OsmAndProtocol.java b/src/main/java/org/traccar/protocol/OsmAndProtocol.java
index d3aa2fd6f..e06580949 100644
--- a/src/main/java/org/traccar/protocol/OsmAndProtocol.java
+++ b/src/main/java/org/traccar/protocol/OsmAndProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class OsmAndProtocol extends BaseProtocol {
- public OsmAndProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public OsmAndProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(16384));
diff --git a/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java b/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java
index ec9bbc240..c8968023a 100644
--- a/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 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.
@@ -21,10 +21,8 @@ import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.QueryStringDecoder;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
-import org.traccar.database.CommandsManager;
import org.traccar.helper.DateUtil;
import org.traccar.model.CellTower;
import org.traccar.model.Command;
@@ -61,6 +59,8 @@ public class OsmAndProtocolDecoder extends BaseHttpProtocolDecoder {
position.setValid(true);
Network network = new Network();
+ Double latitude = null;
+ Double longitude = null;
for (Map.Entry<String, List<String>> entry : params.entrySet()) {
for (String value : entry.getValue()) {
@@ -94,15 +94,15 @@ public class OsmAndProtocolDecoder extends BaseHttpProtocolDecoder {
}
break;
case "lat":
- position.setLatitude(Double.parseDouble(value));
+ latitude = Double.parseDouble(value);
break;
case "lon":
- position.setLongitude(Double.parseDouble(value));
+ longitude = Double.parseDouble(value);
break;
case "location":
String[] location = value.split(",");
- position.setLatitude(Double.parseDouble(location[0]));
- position.setLongitude(Double.parseDouble(location[1]));
+ latitude = Double.parseDouble(location[0]);
+ longitude = Double.parseDouble(location[1]);
break;
case "cell":
String[] cell = value.split(",");
@@ -143,6 +143,9 @@ public class OsmAndProtocolDecoder extends BaseHttpProtocolDecoder {
case "driverUniqueId":
position.set(Position.KEY_DRIVER_UNIQUE_ID, value);
break;
+ case "charge":
+ position.set(Position.KEY_CHARGE, Boolean.parseBoolean(value));
+ break;
default:
try {
position.set(entry.getKey(), Double.parseDouble(value));
@@ -172,17 +175,17 @@ public class OsmAndProtocolDecoder extends BaseHttpProtocolDecoder {
position.setNetwork(network);
}
- if (position.getLatitude() == 0 && position.getLongitude() == 0) {
+ if (latitude != null && longitude != null) {
+ position.setLatitude(latitude);
+ position.setLongitude(longitude);
+ } else {
getLastLocation(position, position.getDeviceTime());
}
if (position.getDeviceId() != 0) {
String response = null;
- CommandsManager commandsManager = Context.getCommandsManager();
- if (commandsManager != null) {
- for (Command command : commandsManager.readQueuedCommands(position.getDeviceId(), 1)) {
- response = command.getString(Command.KEY_DATA);
- }
+ for (Command command : getCommandsManager().readQueuedCommands(position.getDeviceId(), 1)) {
+ response = command.getString(Command.KEY_DATA);
}
if (response != null) {
sendResponse(channel, HttpResponseStatus.OK, Unpooled.copiedBuffer(response, StandardCharsets.UTF_8));
diff --git a/src/main/java/org/traccar/protocol/OutsafeProtocol.java b/src/main/java/org/traccar/protocol/OutsafeProtocol.java
index c728a404d..159534883 100644
--- a/src/main/java/org/traccar/protocol/OutsafeProtocol.java
+++ b/src/main/java/org/traccar/protocol/OutsafeProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class OutsafeProtocol extends BaseProtocol {
- public OutsafeProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public OutsafeProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(65535));
diff --git a/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java b/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java
index 9de77d241..f71778412 100644
--- a/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java
@@ -19,15 +19,15 @@ import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.model.Position;
-import javax.json.Json;
-import javax.json.JsonNumber;
-import javax.json.JsonObject;
-import javax.json.JsonString;
-import javax.json.JsonValue;
+import jakarta.json.Json;
+import jakarta.json.JsonNumber;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonString;
+import jakarta.json.JsonValue;
import java.io.StringReader;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
diff --git a/src/main/java/org/traccar/protocol/OwnTracksProtocol.java b/src/main/java/org/traccar/protocol/OwnTracksProtocol.java
index 0086371d8..c509ad282 100644
--- a/src/main/java/org/traccar/protocol/OwnTracksProtocol.java
+++ b/src/main/java/org/traccar/protocol/OwnTracksProtocol.java
@@ -22,13 +22,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class OwnTracksProtocol extends BaseProtocol {
- public OwnTracksProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public OwnTracksProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(16384));
diff --git a/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java b/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java
index 509d14ae4..e54d07fa7 100644
--- a/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java
@@ -20,13 +20,13 @@ import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
-import javax.json.Json;
-import javax.json.JsonObject;
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
import java.io.StringReader;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
diff --git a/src/main/java/org/traccar/protocol/PacificTrackProtocol.java b/src/main/java/org/traccar/protocol/PacificTrackProtocol.java
index 08991ab64..a315d4d9f 100644
--- a/src/main/java/org/traccar/protocol/PacificTrackProtocol.java
+++ b/src/main/java/org/traccar/protocol/PacificTrackProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class PacificTrackProtocol extends BaseProtocol {
- public PacificTrackProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public PacificTrackProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new PacificTrackProtocolDecoder(PacificTrackProtocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/PacificTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/PacificTrackProtocolDecoder.java
index b5d34a029..7079745be 100644
--- a/src/main/java/org/traccar/protocol/PacificTrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/PacificTrackProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/PathAwayProtocol.java b/src/main/java/org/traccar/protocol/PathAwayProtocol.java
index 6b5d75c5e..a65740475 100644
--- a/src/main/java/org/traccar/protocol/PathAwayProtocol.java
+++ b/src/main/java/org/traccar/protocol/PathAwayProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class PathAwayProtocol extends BaseProtocol {
- public PathAwayProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public PathAwayProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(16384));
diff --git a/src/main/java/org/traccar/protocol/PathAwayProtocolDecoder.java b/src/main/java/org/traccar/protocol/PathAwayProtocolDecoder.java
index 02a15e34a..3e7fa9a5b 100644
--- a/src/main/java/org/traccar/protocol/PathAwayProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/PathAwayProtocolDecoder.java
@@ -24,7 +24,7 @@ import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.QueryStringDecoder;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocol.java b/src/main/java/org/traccar/protocol/PiligrimProtocol.java
index d88c1ab72..9dd1bc491 100644
--- a/src/main/java/org/traccar/protocol/PiligrimProtocol.java
+++ b/src/main/java/org/traccar/protocol/PiligrimProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class PiligrimProtocol extends BaseProtocol {
- public PiligrimProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public PiligrimProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(16384));
diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java
index 26ce2fe53..34c879cb8 100644
--- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2014 - 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.
@@ -22,16 +22,19 @@ import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.QueryStringDecoder;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.DateBuilder;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
import org.traccar.model.Position;
+import org.traccar.session.DeviceSession;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;
+import java.util.regex.Pattern;
public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder {
@@ -47,6 +50,21 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder {
public static final int MSG_GPS_SENSORS = 0xF2;
public static final int MSG_EVENTS = 0xF3;
+ private static final Pattern PATTERN = new PatternBuilder()
+ .expression("[^$]+")
+ .text("$GPRMC,")
+ .number("(dd)(dd)(dd).d+,") // time (hhmmss)
+ .expression("([AV]),") // validity
+ .number("(dd)(dd.d+),") // latitude
+ .expression("([NS]),")
+ .number("(d{2,3})(dd.d+),") // longitude
+ .expression("([EW]),")
+ .number("(d+.d+),") // speed
+ .number("(d+.d+),") // course
+ .number("(dd)(dd)(dd),") // date (ddmmyy)
+ .any()
+ .compile();
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -150,6 +168,42 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder {
}
return positions;
+
+ } else if (uri.startsWith("/push.do")) {
+
+ sendResponse(channel, "PUSH.DO: OK");
+
+ String sentence = request.content().toString(StandardCharsets.US_ASCII);
+
+ String[] parts = sentence.split("&");
+ String phone = parts[1].substring(16);
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, phone);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Parser parser = new Parser(PATTERN, parts[2]);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
+
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
+
+ dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt());
+ position.setTime(dateBuilder.getDate());
+
+ return position;
+
}
return null;
diff --git a/src/main/java/org/traccar/protocol/PluginProtocol.java b/src/main/java/org/traccar/protocol/PluginProtocol.java
index d5f28da9d..fff1830e8 100644
--- a/src/main/java/org/traccar/protocol/PluginProtocol.java
+++ b/src/main/java/org/traccar/protocol/PluginProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class PluginProtocol extends BaseProtocol {
- public PluginProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public PluginProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java b/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java
index 65de211ac..6ee95d18a 100644
--- a/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/PluginProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/PolteProtocol.java b/src/main/java/org/traccar/protocol/PolteProtocol.java
index a3e548716..0fbedfb09 100644
--- a/src/main/java/org/traccar/protocol/PolteProtocol.java
+++ b/src/main/java/org/traccar/protocol/PolteProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class PolteProtocol extends BaseProtocol {
- public PolteProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public PolteProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(65535));
diff --git a/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java b/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java
index ce45abef6..8954db491 100644
--- a/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java
@@ -19,12 +19,12 @@ import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.model.Position;
-import javax.json.Json;
-import javax.json.JsonObject;
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
import java.io.StringReader;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
diff --git a/src/main/java/org/traccar/protocol/PortmanProtocol.java b/src/main/java/org/traccar/protocol/PortmanProtocol.java
index b7faae08a..3a4b49289 100644
--- a/src/main/java/org/traccar/protocol/PortmanProtocol.java
+++ b/src/main/java/org/traccar/protocol/PortmanProtocol.java
@@ -21,17 +21,21 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class PortmanProtocol extends BaseProtocol {
- public PortmanProtocol() {
+ @Inject
+ public PortmanProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/PortmanProtocolDecoder.java b/src/main/java/org/traccar/protocol/PortmanProtocolDecoder.java
index e1847a2b2..da9403313 100644
--- a/src/main/java/org/traccar/protocol/PortmanProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/PortmanProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/PretraceProtocol.java b/src/main/java/org/traccar/protocol/PretraceProtocol.java
index 9d35c1c2f..54a34fc69 100644
--- a/src/main/java/org/traccar/protocol/PretraceProtocol.java
+++ b/src/main/java/org/traccar/protocol/PretraceProtocol.java
@@ -21,17 +21,21 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class PretraceProtocol extends BaseProtocol {
- public PretraceProtocol() {
+ @Inject
+ public PretraceProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_POSITION_PERIODIC);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ')'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/PretraceProtocolDecoder.java b/src/main/java/org/traccar/protocol/PretraceProtocolDecoder.java
index a19384e62..ff6ad763a 100644
--- a/src/main/java/org/traccar/protocol/PretraceProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/PretraceProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/PretraceProtocolEncoder.java b/src/main/java/org/traccar/protocol/PretraceProtocolEncoder.java
index 1083a252e..a109e7a07 100644
--- a/src/main/java/org/traccar/protocol/PretraceProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/PretraceProtocolEncoder.java
@@ -16,10 +16,9 @@
package org.traccar.protocol;
import org.traccar.BaseProtocolEncoder;
-import org.traccar.Context;
+import org.traccar.Protocol;
import org.traccar.helper.Checksum;
import org.traccar.model.Command;
-import org.traccar.Protocol;
public class PretraceProtocolEncoder extends BaseProtocolEncoder {
@@ -35,7 +34,7 @@ public class PretraceProtocolEncoder extends BaseProtocolEncoder {
@Override
protected Object encodeCommand(Command command) {
- String uniqueId = Context.getIdentityManager().getById(command.getDeviceId()).getUniqueId();
+ String uniqueId = getUniqueId(command.getDeviceId());
switch (command.getType()) {
case Command.TYPE_CUSTOM:
diff --git a/src/main/java/org/traccar/protocol/PricolProtocol.java b/src/main/java/org/traccar/protocol/PricolProtocol.java
index 6821cd949..7b0e7386c 100644
--- a/src/main/java/org/traccar/protocol/PricolProtocol.java
+++ b/src/main/java/org/traccar/protocol/PricolProtocol.java
@@ -19,20 +19,24 @@ import io.netty.handler.codec.FixedLengthFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class PricolProtocol extends BaseProtocol {
- public PricolProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public PricolProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new FixedLengthFrameDecoder(64));
pipeline.addLast(new PricolProtocolDecoder(PricolProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new PricolProtocolDecoder(PricolProtocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/PricolProtocolDecoder.java b/src/main/java/org/traccar/protocol/PricolProtocolDecoder.java
index 190c68258..5f6805f09 100644
--- a/src/main/java/org/traccar/protocol/PricolProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/PricolProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/ProgressProtocol.java b/src/main/java/org/traccar/protocol/ProgressProtocol.java
index aac84205d..8d159ef24 100644
--- a/src/main/java/org/traccar/protocol/ProgressProtocol.java
+++ b/src/main/java/org/traccar/protocol/ProgressProtocol.java
@@ -19,14 +19,18 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import java.nio.ByteOrder;
+import jakarta.inject.Inject;
+
public class ProgressProtocol extends BaseProtocol {
- public ProgressProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public ProgressProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, 4, 0, true));
pipeline.addLast(new ProgressProtocolDecoder(ProgressProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/ProgressProtocolDecoder.java b/src/main/java/org/traccar/protocol/ProgressProtocolDecoder.java
index 0025cd9e7..e3a5881da 100644
--- a/src/main/java/org/traccar/protocol/ProgressProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ProgressProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/PstProtocol.java b/src/main/java/org/traccar/protocol/PstProtocol.java
index d8c7008cb..01a83b31f 100644
--- a/src/main/java/org/traccar/protocol/PstProtocol.java
+++ b/src/main/java/org/traccar/protocol/PstProtocol.java
@@ -18,24 +18,28 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class PstProtocol extends BaseProtocol {
- public PstProtocol() {
+ @Inject
+ public PstProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME);
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new PstProtocolEncoder(PstProtocol.this));
pipeline.addLast(new PstProtocolDecoder(PstProtocol.this));
}
});
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new PstFrameEncoder());
pipeline.addLast(new PstFrameDecoder());
pipeline.addLast(new PstProtocolEncoder(PstProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/PstProtocolDecoder.java b/src/main/java/org/traccar/protocol/PstProtocolDecoder.java
index e3fe1af62..872e77a3a 100644
--- a/src/main/java/org/traccar/protocol/PstProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/PstProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/Pt215Protocol.java b/src/main/java/org/traccar/protocol/Pt215Protocol.java
index 09bd9b121..fd67b1241 100644
--- a/src/main/java/org/traccar/protocol/Pt215Protocol.java
+++ b/src/main/java/org/traccar/protocol/Pt215Protocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Pt215Protocol extends BaseProtocol {
- public Pt215Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Pt215Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 1, -1, 0));
pipeline.addLast(new Pt215ProtocolDecoder(Pt215Protocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/Pt215ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Pt215ProtocolDecoder.java
index 48ce7dede..f669c5ffd 100644
--- a/src/main/java/org/traccar/protocol/Pt215ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Pt215ProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/Pt3000Protocol.java b/src/main/java/org/traccar/protocol/Pt3000Protocol.java
index 1ad0026a3..5f49084ed 100644
--- a/src/main/java/org/traccar/protocol/Pt3000Protocol.java
+++ b/src/main/java/org/traccar/protocol/Pt3000Protocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Pt3000Protocol extends BaseProtocol {
- public Pt3000Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Pt3000Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, 'd')); // probably wrong
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/Pt3000ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Pt3000ProtocolDecoder.java
index e7f9e062a..c33660f51 100644
--- a/src/main/java/org/traccar/protocol/Pt3000ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Pt3000ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/Pt502Protocol.java b/src/main/java/org/traccar/protocol/Pt502Protocol.java
index 56444fb42..0257dd60f 100644
--- a/src/main/java/org/traccar/protocol/Pt502Protocol.java
+++ b/src/main/java/org/traccar/protocol/Pt502Protocol.java
@@ -19,20 +19,24 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class Pt502Protocol extends BaseProtocol {
- public Pt502Protocol() {
+ @Inject
+ public Pt502Protocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_SET_TIMEZONE,
Command.TYPE_ALARM_SPEED,
Command.TYPE_OUTPUT_CONTROL,
Command.TYPE_REQUEST_PHOTO);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new Pt502FrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new Pt502ProtocolEncoder(Pt502Protocol.this));
diff --git a/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java
index ff92b51f1..2a6a81a65 100644
--- a/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Pt502ProtocolDecoder.java
@@ -20,8 +20,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
@@ -175,14 +174,13 @@ public class Pt502ProtocolDecoder extends BaseProtocolDecoder {
} else {
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
- String uniqueId = Context.getIdentityManager().getById(deviceSession.getDeviceId()).getUniqueId();
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
getLastLocation(position, null);
- position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(uniqueId, photo, "jpg"));
+ position.set(Position.KEY_IMAGE, writeMediaFile(deviceSession.getUniqueId(), photo, "jpg"));
photo.release();
photo = null;
diff --git a/src/main/java/org/traccar/protocol/Pt60Protocol.java b/src/main/java/org/traccar/protocol/Pt60Protocol.java
index c502426c5..83e3bfbeb 100644
--- a/src/main/java/org/traccar/protocol/Pt60Protocol.java
+++ b/src/main/java/org/traccar/protocol/Pt60Protocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Pt60Protocol extends BaseProtocol {
- public Pt60Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Pt60Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "@R#@", "@E#@"));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/Pt60ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Pt60ProtocolDecoder.java
index 6a3fe2734..94b549fe6 100644
--- a/src/main/java/org/traccar/protocol/Pt60ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Pt60ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/R12wProtocol.java b/src/main/java/org/traccar/protocol/R12wProtocol.java
index 3726233b4..b5b3eff81 100644
--- a/src/main/java/org/traccar/protocol/R12wProtocol.java
+++ b/src/main/java/org/traccar/protocol/R12wProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class R12wProtocol extends BaseProtocol {
- public R12wProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public R12wProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/R12wProtocolDecoder.java b/src/main/java/org/traccar/protocol/R12wProtocolDecoder.java
index d60318447..3be784911 100644
--- a/src/main/java/org/traccar/protocol/R12wProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/R12wProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Checksum;
diff --git a/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java b/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java
index c9db10610..6f7340902 100644
--- a/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java
+++ b/src/main/java/org/traccar/protocol/RaceDynamicsProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class RaceDynamicsProtocol extends BaseProtocol {
- public RaceDynamicsProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public RaceDynamicsProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1500));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/RaceDynamicsProtocolDecoder.java b/src/main/java/org/traccar/protocol/RaceDynamicsProtocolDecoder.java
index f441bf8ed..89639ad30 100644
--- a/src/main/java/org/traccar/protocol/RaceDynamicsProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/RaceDynamicsProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/RadarProtocol.java b/src/main/java/org/traccar/protocol/RadarProtocol.java
index 9783778f0..8985e0e83 100644
--- a/src/main/java/org/traccar/protocol/RadarProtocol.java
+++ b/src/main/java/org/traccar/protocol/RadarProtocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class RadarProtocol extends BaseProtocol {
- public RadarProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public RadarProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 12, 2, -14, 0));
pipeline.addLast(new RadarProtocolDecoder(RadarProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/RadarProtocolDecoder.java b/src/main/java/org/traccar/protocol/RadarProtocolDecoder.java
index d87f77b84..818e97f8b 100644
--- a/src/main/java/org/traccar/protocol/RadarProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/RadarProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.UnitsConverter;
diff --git a/src/main/java/org/traccar/protocol/RaveonProtocol.java b/src/main/java/org/traccar/protocol/RaveonProtocol.java
index 44faadb3b..aa1a79219 100644
--- a/src/main/java/org/traccar/protocol/RaveonProtocol.java
+++ b/src/main/java/org/traccar/protocol/RaveonProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class RaveonProtocol extends BaseProtocol {
- public RaveonProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public RaveonProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/RaveonProtocolDecoder.java b/src/main/java/org/traccar/protocol/RaveonProtocolDecoder.java
index 50acd20a1..dfc21bf69 100644
--- a/src/main/java/org/traccar/protocol/RaveonProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/RaveonProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/RecodaProtocol.java b/src/main/java/org/traccar/protocol/RecodaProtocol.java
index 0bc9870bc..7d2fadae4 100644
--- a/src/main/java/org/traccar/protocol/RecodaProtocol.java
+++ b/src/main/java/org/traccar/protocol/RecodaProtocol.java
@@ -19,14 +19,18 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import java.nio.ByteOrder;
+import jakarta.inject.Inject;
+
public class RecodaProtocol extends BaseProtocol {
- public RecodaProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public RecodaProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 4, 4, -8, 0, true));
pipeline.addLast(new RecodaProtocolDecoder(RecodaProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/RecodaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RecodaProtocolDecoder.java
index 04098225f..0c417a62f 100644
--- a/src/main/java/org/traccar/protocol/RecodaProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/RecodaProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.UnitsConverter;
diff --git a/src/main/java/org/traccar/protocol/RetranslatorProtocol.java b/src/main/java/org/traccar/protocol/RetranslatorProtocol.java
index fae81f7d2..a349a8191 100644
--- a/src/main/java/org/traccar/protocol/RetranslatorProtocol.java
+++ b/src/main/java/org/traccar/protocol/RetranslatorProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class RetranslatorProtocol extends BaseProtocol {
- public RetranslatorProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public RetranslatorProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new RetranslatorFrameDecoder());
pipeline.addLast(new RetranslatorProtocolDecoder(RetranslatorProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/RetranslatorProtocolDecoder.java b/src/main/java/org/traccar/protocol/RetranslatorProtocolDecoder.java
index 5bf6cef50..afbf7e511 100644
--- a/src/main/java/org/traccar/protocol/RetranslatorProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/RetranslatorProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.model.Position;
diff --git a/src/main/java/org/traccar/protocol/RfTrackProtocol.java b/src/main/java/org/traccar/protocol/RfTrackProtocol.java
new file mode 100644
index 000000000..ac033c348
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/RfTrackProtocol.java
@@ -0,0 +1,43 @@
+/*
+ * 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.protocol;
+
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
+
+public class RfTrackProtocol extends BaseProtocol {
+
+ @Inject
+ public RfTrackProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new HttpResponseEncoder());
+ pipeline.addLast(new HttpRequestDecoder());
+ pipeline.addLast(new HttpObjectAggregator(16384));
+ pipeline.addLast(new RfTrackProtocolDecoder(RfTrackProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/RfTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/RfTrackProtocolDecoder.java
new file mode 100644
index 000000000..cbb204e3b
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/RfTrackProtocolDecoder.java
@@ -0,0 +1,163 @@
+/*
+ * 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.protocol;
+
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.QueryStringDecoder;
+import org.traccar.BaseHttpProtocolDecoder;
+import org.traccar.Protocol;
+import org.traccar.model.CellTower;
+import org.traccar.model.Command;
+import org.traccar.model.Network;
+import org.traccar.model.Position;
+import org.traccar.model.WifiAccessPoint;
+import org.traccar.session.DeviceSession;
+
+import jakarta.json.Json;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import java.io.StringReader;
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+public class RfTrackProtocolDecoder extends BaseHttpProtocolDecoder {
+
+ public RfTrackProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ FullHttpRequest request = (FullHttpRequest) msg;
+ QueryStringDecoder decoder = new QueryStringDecoder(
+ request.content().toString(StandardCharsets.US_ASCII), false);
+ Map<String, List<String>> params = decoder.parameters();
+
+ Position position = new Position(getProtocolName());
+ Network network = new Network();
+
+ for (Map.Entry<String, List<String>> entry : params.entrySet()) {
+ for (String value : entry.getValue()) {
+ switch (entry.getKey()) {
+ case "i":
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, value);
+ if (deviceSession == null) {
+ sendResponse(channel, HttpResponseStatus.BAD_REQUEST);
+ return null;
+ }
+ position.setDeviceId(deviceSession.getDeviceId());
+ break;
+ case "v":
+ position.set(Position.KEY_VERSION_FW, value);
+ break;
+ case "t":
+ position.setDeviceTime(new Date(Long.parseLong(value)));
+ break;
+ case "bat":
+ int battery = Integer.parseInt(value);
+ position.set(Position.KEY_BATTERY_LEVEL, battery & 0xff);
+ position.set("plugStatus", (battery >> 8) & 0x0f);
+ position.set(Position.KEY_CHARGE, ((battery >> 12) & 0x0f) == 1);
+ break;
+ case "id":
+ position.set("braceletId", value);
+ break;
+ case "rc":
+ int braceletCode = Integer.parseInt(value);
+ position.set("braceletCode", braceletCode & 0xffff);
+ position.set("braceletStatus", braceletCode >> 16);
+ break;
+ case "idt":
+ long braceletTime = Long.parseLong(value);
+ position.set("lastHeartbeat", (braceletTime >> 45) * 10);
+ position.set("lastPaired", ((braceletTime >> 30) & 0xffff) * 10);
+ position.set("lastUnpaired", ((braceletTime >> 15) & 0xffff) * 10);
+ break;
+ case "mt":
+ int vibrationTime = Integer.parseInt(value);
+ position.set("vibrationDevice", (vibrationTime & 0x7fff) * 10);
+ position.set("vibrationBracelet", (vibrationTime >> 15) * 10);
+ break;
+ case "gps":
+ JsonObject location = Json.createReader(new StringReader(value)).readObject();
+ position.setValid(true);
+ position.setAccuracy(location.getJsonNumber("a").doubleValue());
+ position.setLongitude(location.getJsonNumber("x").doubleValue());
+ position.setLatitude(location.getJsonNumber("y").doubleValue());
+ position.setAltitude(location.getJsonNumber("z").doubleValue());
+ position.setFixTime(new Date(location.getJsonNumber("t").longValue()));
+ break;
+ case "gsm":
+ JsonObject cellInfo = Json.createReader(new StringReader(value)).readObject();
+ int mcc = cellInfo.getInt("c");
+ int mnc = cellInfo.getInt("n");
+ JsonArray cells = cellInfo.getJsonArray("b");
+ for (int i = 0; i < cells.size(); i++) {
+ JsonObject cell = cells.getJsonObject(i);
+ network.addCellTower(CellTower.from(
+ mcc, mnc, cell.getInt("l"), cell.getInt("c"), cell.getInt("b")));
+ }
+ break;
+ case "dbm":
+ position.set(Position.KEY_RSSI, Integer.parseInt(value));
+ break;
+ case "bar":
+ position.set("pressure", Double.parseDouble(value));
+ break;
+ case "cob":
+ position.set("pressureChanges", value);
+ break;
+ case "wifi":
+ JsonArray wifiInfo = Json.createReader(new StringReader(value)).readArray();
+ for (int i = 0; i < wifiInfo.size(); i++) {
+ JsonObject wifi = wifiInfo.getJsonObject(i);
+ network.addWifiAccessPoint(WifiAccessPoint.from(
+ wifi.getString("m").replace('-', ':'), wifi.getInt("l")));
+ }
+ break;
+ case "u_ids":
+ position.set("unpairedIds", value);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (position.getFixTime() == null) {
+ getLastLocation(position, position.getDeviceTime());
+ }
+
+ if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) {
+ position.setNetwork(network);
+ }
+
+ String response = "{}";
+ for (Command command : getCommandsManager().readQueuedCommands(position.getDeviceId(), 1)) {
+ response = command.getString(Command.KEY_DATA);
+ }
+ sendResponse(channel, HttpResponseStatus.OK, Unpooled.copiedBuffer(response, StandardCharsets.UTF_8));
+ return position;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/RitiProtocol.java b/src/main/java/org/traccar/protocol/RitiProtocol.java
index de1026672..9916042a8 100644
--- a/src/main/java/org/traccar/protocol/RitiProtocol.java
+++ b/src/main/java/org/traccar/protocol/RitiProtocol.java
@@ -19,14 +19,18 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import java.nio.ByteOrder;
+import jakarta.inject.Inject;
+
public class RitiProtocol extends BaseProtocol {
- public RitiProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public RitiProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 105, 2, 3, 0, true));
pipeline.addLast(new RitiProtocolDecoder(RitiProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/RitiProtocolDecoder.java b/src/main/java/org/traccar/protocol/RitiProtocolDecoder.java
index 46267ca90..501d5faa7 100644
--- a/src/main/java/org/traccar/protocol/RitiProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/RitiProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/RoboTrackProtocol.java b/src/main/java/org/traccar/protocol/RoboTrackProtocol.java
index c2c531293..229c343bb 100644
--- a/src/main/java/org/traccar/protocol/RoboTrackProtocol.java
+++ b/src/main/java/org/traccar/protocol/RoboTrackProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class RoboTrackProtocol extends BaseProtocol {
- public RoboTrackProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public RoboTrackProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new RoboTrackFrameDecoder());
pipeline.addLast(new RoboTrackProtocolDecoder(RoboTrackProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/RoboTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/RoboTrackProtocolDecoder.java
index b613f31d7..ffe16bd7b 100644
--- a/src/main/java/org/traccar/protocol/RoboTrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/RoboTrackProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/RstProtocol.java b/src/main/java/org/traccar/protocol/RstProtocol.java
index 10d11d493..0bb809a49 100644
--- a/src/main/java/org/traccar/protocol/RstProtocol.java
+++ b/src/main/java/org/traccar/protocol/RstProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class RstProtocol extends BaseProtocol {
- public RstProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public RstProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new RstProtocolDecoder(RstProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java
index 9e3261a04..fcc96fbf1 100644
--- a/src/main/java/org/traccar/protocol/RstProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/RstProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocol.java b/src/main/java/org/traccar/protocol/RuptelaProtocol.java
index 5d1f86553..9f399e299 100644
--- a/src/main/java/org/traccar/protocol/RuptelaProtocol.java
+++ b/src/main/java/org/traccar/protocol/RuptelaProtocol.java
@@ -19,11 +19,15 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class RuptelaProtocol extends BaseProtocol {
- public RuptelaProtocol() {
+ @Inject
+ public RuptelaProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_ENGINE_STOP,
@@ -35,9 +39,9 @@ public class RuptelaProtocol extends BaseProtocol {
Command.TYPE_OUTPUT_CONTROL,
Command.TYPE_SET_CONNECTION,
Command.TYPE_SET_ODOMETER);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 2, 2, 0));
pipeline.addLast(new RuptelaProtocolEncoder(RuptelaProtocol.this));
pipeline.addLast(new RuptelaProtocolDecoder(RuptelaProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java
index 2812d22ff..649de7c5c 100644
--- a/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/RuptelaProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 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.
@@ -19,10 +19,10 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
+import org.traccar.helper.BitUtil;
import org.traccar.helper.DataConverter;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
@@ -50,6 +50,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_SMS_VIA_GPRS_RESPONSE = 7;
public static final int MSG_SMS_VIA_GPRS = 8;
public static final int MSG_DTCS = 9;
+ public static final int MSG_IDENTIFICATION = 15;
public static final int MSG_SET_IO = 17;
public static final int MSG_FILES = 37;
public static final int MSG_EXTENDED_RECORDS = 68;
@@ -92,22 +93,48 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
}
}
+ private void decodeDriver(Position position, String part1, String part2) {
+ Long driverIdPart1 = (Long) position.getAttributes().remove(part1);
+ Long driverIdPart2 = (Long) position.getAttributes().remove(part2);
+ if (driverIdPart1 != null && driverIdPart2 != null) {
+ ByteBuf driverId = Unpooled.copyLong(driverIdPart1, driverIdPart2);
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, driverId.toString(StandardCharsets.US_ASCII));
+ driverId.release();
+ }
+ }
+
private void decodeParameter(Position position, int id, ByteBuf buf, int length) {
switch (id) {
case 2:
case 3:
case 4:
- position.set("di" + (id - 1), readValue(buf, length, false));
- break;
case 5:
- position.set(Position.KEY_IGNITION, readValue(buf, length, false) == 1);
+ position.set(Position.PREFIX_IN + (id - 1), readValue(buf, length, false));
+ break;
+ case 20:
+ position.set(Position.PREFIX_ADC + 3, readValue(buf, length, false));
+ break;
+ case 21:
+ position.set(Position.PREFIX_ADC + 4, readValue(buf, length, false));
+ break;
+ case 22:
+ position.set(Position.PREFIX_ADC + 1, readValue(buf, length, false));
+ break;
+ case 23:
+ position.set(Position.PREFIX_ADC + 2, readValue(buf, length, false));
break;
case 29:
- position.set(Position.KEY_POWER, readValue(buf, length, false));
+ position.set(Position.KEY_POWER, readValue(buf, length, false) * 0.001);
break;
case 30:
position.set(Position.KEY_BATTERY, readValue(buf, length, false) * 0.001);
break;
+ case 32:
+ position.set(Position.KEY_DEVICE_TEMP, readValue(buf, length, true));
+ break;
+ case 65:
+ position.set(Position.KEY_ODOMETER, readValue(buf, length, true));
+ break;
case 74:
position.set(Position.PREFIX_TEMP + 3, readValue(buf, length, true) * 0.1);
break;
@@ -116,6 +143,14 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
case 80:
position.set(Position.PREFIX_TEMP + (id - 78), readValue(buf, length, true) * 0.1);
break;
+ case 88:
+ if (readValue(buf, length, false) > 0) {
+ position.set(Position.KEY_ALARM, Position.ALARM_JAMMING);
+ }
+ break;
+ case 95:
+ position.set(Position.KEY_OBD_SPEED, UnitsConverter.knotsFromKph(readValue(buf, length, true)));
+ break;
case 134:
if (readValue(buf, length, false) > 0) {
position.set(Position.KEY_ALARM, Position.ALARM_BRAKING);
@@ -126,9 +161,45 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
}
break;
+ case 150:
+ position.set(Position.KEY_OPERATOR, readValue(buf, length, false));
+ break;
+ case 170:
+ position.set(Position.KEY_CHARGE, readValue(buf, length, false) > 0);
+ break;
+ case 173:
+ position.set(Position.KEY_MOTION, readValue(buf, length, false) > 0);
+ break;
case 197:
position.set(Position.KEY_RPM, readValue(buf, length, false) * 0.125);
break;
+ case 251:
+ case 409:
+ position.set(Position.KEY_IGNITION, readValue(buf, length, false) > 0);
+ break;
+ case 410:
+ if (readValue(buf, length, false) > 0) {
+ position.set(Position.KEY_ALARM, Position.ALARM_TOW);
+ }
+ break;
+ case 411:
+ if (readValue(buf, length, false) > 0) {
+ position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT);
+ }
+ break;
+ case 415:
+ if (readValue(buf, length, false) == 0) {
+ position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT);
+ }
+ break;
+ case 645:
+ position.set(Position.KEY_OBD_ODOMETER, readValue(buf, length, true) * 1000);
+ break;
+ case 758:
+ if (readValue(buf, length, false) == 1) {
+ position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING);
+ }
+ break;
default:
position.set(Position.PREFIX_IO + id, readValue(buf, length, false));
break;
@@ -166,22 +237,32 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedByte(); // timestamp extension
if (type == MSG_EXTENDED_RECORDS) {
- buf.readUnsignedByte(); // record extension
+ int recordExtension = buf.readUnsignedByte();
+ int mergeRecordCount = BitUtil.from(recordExtension, 4);
+ int currentRecord = BitUtil.to(recordExtension, 4);
+
+ if (currentRecord > 0 && currentRecord <= mergeRecordCount) {
+ position = positions.remove(positions.size() - 1);
+ }
}
buf.readUnsignedByte(); // priority (reserved)
- position.setValid(true);
- position.setLongitude(buf.readInt() / 10000000.0);
- position.setLatitude(buf.readInt() / 10000000.0);
- position.setAltitude(buf.readUnsignedShort() / 10.0);
- position.setCourse(buf.readUnsignedShort() / 100.0);
-
- position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
-
- position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort()));
-
- position.set(Position.KEY_HDOP, buf.readUnsignedByte() / 10.0);
+ int longitude = buf.readInt();
+ int latitude = buf.readInt();
+ if (longitude > Integer.MIN_VALUE && latitude > Integer.MIN_VALUE) {
+ position.setValid(true);
+ position.setLongitude(longitude / 10000000.0);
+ position.setLatitude(latitude / 10000000.0);
+ position.setAltitude(buf.readUnsignedShort() / 10.0);
+ position.setCourse(buf.readUnsignedShort() / 100.0);
+ position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort()));
+ position.set(Position.KEY_HDOP, buf.readUnsignedByte() / 10.0);
+ } else {
+ buf.skipBytes(8);
+ getLastLocation(position, null);
+ }
if (type == MSG_EXTENDED_RECORDS) {
position.set(Position.KEY_EVENT, buf.readUnsignedShort());
@@ -217,12 +298,13 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
decodeParameter(position, id, buf, 8);
}
- Long driverIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 126);
- Long driverIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 127);
- if (driverIdPart1 != null && driverIdPart2 != null) {
- ByteBuf driverId = Unpooled.copyLong(driverIdPart1, driverIdPart2);
- position.set(Position.KEY_DRIVER_UNIQUE_ID, driverId.toString(StandardCharsets.US_ASCII));
- driverId.release();
+ decodeDriver(position, Position.PREFIX_IO + 126, Position.PREFIX_IO + 127); // can driver
+ decodeDriver(position, Position.PREFIX_IO + 155, Position.PREFIX_IO + 156); // tco driver
+
+ Long tagIdPart1 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 760);
+ Long tagIdPart2 = (Long) position.getAttributes().remove(Position.PREFIX_IO + 761);
+ if (tagIdPart1 != null && tagIdPart2 != null) {
+ position.set("tagId", Long.toHexString(tagIdPart1) + Long.toHexString(tagIdPart2));
}
positions.add(position);
@@ -297,7 +379,7 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
getLastLocation(position, null);
- position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(imei, photo, "jpg"));
+ position.set(Position.KEY_IMAGE, writeMediaFile(imei, photo, "jpg"));
photo.release();
photo = null;
return position;
@@ -306,6 +388,18 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
return null;
+ } else if (type == MSG_IDENTIFICATION) {
+
+ ByteBuf content = Unpooled.buffer();
+ content.writeByte(1);
+ ByteBuf response = RuptelaProtocolEncoder.encodeContent(type, content);
+ content.release();
+ if (channel != null) {
+ channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
+ }
+
+ return null;
+
} else {
return decodeCommandResponse(deviceSession, type, buf);
diff --git a/src/main/java/org/traccar/protocol/RuptelaProtocolEncoder.java b/src/main/java/org/traccar/protocol/RuptelaProtocolEncoder.java
index 442961b19..5ec971a98 100644
--- a/src/main/java/org/traccar/protocol/RuptelaProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/RuptelaProtocolEncoder.java
@@ -80,14 +80,14 @@ public class RuptelaProtocolEncoder extends BaseProtocolEncoder {
return encodeContent(RuptelaProtocolDecoder.MSG_FIRMWARE_UPDATE, content);
case Command.TYPE_OUTPUT_CONTROL:
content.writeInt(command.getInteger(Command.KEY_INDEX));
- content.writeInt(Integer.parseInt(command.getString(Command.KEY_DATA)));
+ content.writeInt(command.getInteger(Command.KEY_DATA));
return encodeContent(RuptelaProtocolDecoder.MSG_SET_IO, content);
case Command.TYPE_SET_CONNECTION:
String c = command.getString(Command.KEY_SERVER) + "," + command.getInteger(Command.KEY_PORT) + ",TCP";
content.writeBytes(c.getBytes(StandardCharsets.US_ASCII));
return encodeContent(RuptelaProtocolDecoder.MSG_SET_CONNECTION, content);
case Command.TYPE_SET_ODOMETER:
- content.writeInt(Integer.parseInt(command.getString(Command.KEY_DATA)));
+ content.writeInt(command.getInteger(Command.KEY_DATA));
return encodeContent(RuptelaProtocolDecoder.MSG_SET_ODOMETER, content);
default:
return null;
diff --git a/src/main/java/org/traccar/protocol/S168Protocol.java b/src/main/java/org/traccar/protocol/S168Protocol.java
index e78664c40..5fb0c6e72 100644
--- a/src/main/java/org/traccar/protocol/S168Protocol.java
+++ b/src/main/java/org/traccar/protocol/S168Protocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class S168Protocol extends BaseProtocol {
- public S168Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public S168Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '$'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/S168ProtocolDecoder.java b/src/main/java/org/traccar/protocol/S168ProtocolDecoder.java
index 6d565517b..cf665c6ba 100644
--- a/src/main/java/org/traccar/protocol/S168ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/S168ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.CellTower;
@@ -107,7 +107,7 @@ public class S168ProtocolDecoder extends BaseProtocolDecoder {
if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) {
position.setNetwork(network);
}
- if (!position.getAttributes().containsKey(Position.KEY_SATELLITES)) {
+ if (!position.hasAttribute(Position.KEY_SATELLITES)) {
getLastLocation(position, null);
}
diff --git a/src/main/java/org/traccar/protocol/SabertekProtocol.java b/src/main/java/org/traccar/protocol/SabertekProtocol.java
index 0ec847b60..cb3f2ab32 100644
--- a/src/main/java/org/traccar/protocol/SabertekProtocol.java
+++ b/src/main/java/org/traccar/protocol/SabertekProtocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.string.StringDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class SabertekProtocol extends BaseProtocol {
- public SabertekProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public SabertekProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new SabertekFrameDecoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new SabertekProtocolDecoder(SabertekProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/SabertekProtocolDecoder.java b/src/main/java/org/traccar/protocol/SabertekProtocolDecoder.java
index 3033aa2cc..71279812c 100644
--- a/src/main/java/org/traccar/protocol/SabertekProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SabertekProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/SanavProtocol.java b/src/main/java/org/traccar/protocol/SanavProtocol.java
index 6799c57e6..ac1941725 100644
--- a/src/main/java/org/traccar/protocol/SanavProtocol.java
+++ b/src/main/java/org/traccar/protocol/SanavProtocol.java
@@ -20,21 +20,25 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class SanavProtocol extends BaseProtocol {
- public SanavProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public SanavProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new SanavProtocolDecoder(SanavProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new SanavProtocolDecoder(SanavProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/SanavProtocolDecoder.java b/src/main/java/org/traccar/protocol/SanavProtocolDecoder.java
index 7e1c158e6..6741cb67c 100644
--- a/src/main/java/org/traccar/protocol/SanavProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SanavProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/SanulProtocol.java b/src/main/java/org/traccar/protocol/SanulProtocol.java
index 3104e9366..cba162296 100644
--- a/src/main/java/org/traccar/protocol/SanulProtocol.java
+++ b/src/main/java/org/traccar/protocol/SanulProtocol.java
@@ -19,15 +19,19 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import java.nio.ByteOrder;
+import jakarta.inject.Inject;
+
public class SanulProtocol extends BaseProtocol {
- public SanulProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public SanulProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 3, 2, 0, 0, true));
pipeline.addLast(new SanulProtocolDecoder(SanulProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/SanulProtocolDecoder.java b/src/main/java/org/traccar/protocol/SanulProtocolDecoder.java
index 036d1ee51..9568cd6d3 100644
--- a/src/main/java/org/traccar/protocol/SanulProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SanulProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.model.Position;
diff --git a/src/main/java/org/traccar/protocol/SatsolProtocol.java b/src/main/java/org/traccar/protocol/SatsolProtocol.java
index b69fdd1fe..7252f99f0 100644
--- a/src/main/java/org/traccar/protocol/SatsolProtocol.java
+++ b/src/main/java/org/traccar/protocol/SatsolProtocol.java
@@ -19,15 +19,19 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import java.nio.ByteOrder;
+import jakarta.inject.Inject;
+
public class SatsolProtocol extends BaseProtocol {
- public SatsolProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public SatsolProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1400, 8, 2, 0, 0, true));
pipeline.addLast(new SatsolProtocolDecoder(SatsolProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/SatsolProtocolDecoder.java b/src/main/java/org/traccar/protocol/SatsolProtocolDecoder.java
index c457d5620..37a84be04 100644
--- a/src/main/java/org/traccar/protocol/SatsolProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SatsolProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocol.java b/src/main/java/org/traccar/protocol/SigfoxProtocol.java
index e2f2cbe1f..edd624727 100644
--- a/src/main/java/org/traccar/protocol/SigfoxProtocol.java
+++ b/src/main/java/org/traccar/protocol/SigfoxProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class SigfoxProtocol extends BaseProtocol {
- public SigfoxProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public SigfoxProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(65535));
diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java
index ce577f392..1298112d1 100644
--- a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java
@@ -22,7 +22,8 @@ import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.helper.BufferUtil;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.DataConverter;
@@ -31,11 +32,11 @@ import org.traccar.model.Network;
import org.traccar.model.Position;
import org.traccar.model.WifiAccessPoint;
-import javax.json.Json;
-import javax.json.JsonNumber;
-import javax.json.JsonObject;
-import javax.json.JsonString;
-import javax.json.JsonValue;
+import jakarta.json.Json;
+import jakarta.json.JsonNumber;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonString;
+import jakarta.json.JsonValue;
import java.io.StringReader;
import java.net.SocketAddress;
import java.net.URLDecoder;
@@ -159,18 +160,8 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder {
if (event == 0x0f || event == 0x1f) {
position.setValid(event >> 4 > 0);
-
- long value;
- value = buf.readUnsignedInt();
- position.setLatitude(BitUtil.to(value, 31) * 0.000001);
- if (BitUtil.check(value, 31)) {
- position.setLatitude(-position.getLatitude());
- }
- value = buf.readUnsignedInt();
- position.setLongitude(BitUtil.to(value, 31) * 0.000001);
- if (BitUtil.check(value, 31)) {
- position.setLongitude(-position.getLongitude());
- }
+ position.setLatitude(BufferUtil.readSignedMagnitudeInt(buf) * 0.000001);
+ position.setLongitude(BufferUtil.readSignedMagnitudeInt(buf) * 0.000001);
position.set(Position.KEY_BATTERY, (int) buf.readUnsignedByte());
diff --git a/src/main/java/org/traccar/protocol/SiwiProtocol.java b/src/main/java/org/traccar/protocol/SiwiProtocol.java
index 8963721c8..59b96bf72 100644
--- a/src/main/java/org/traccar/protocol/SiwiProtocol.java
+++ b/src/main/java/org/traccar/protocol/SiwiProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class SiwiProtocol extends BaseProtocol {
- public SiwiProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public SiwiProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new SiwiProtocolDecoder(SiwiProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/SiwiProtocolDecoder.java b/src/main/java/org/traccar/protocol/SiwiProtocolDecoder.java
index bf8bfab77..7ba501834 100644
--- a/src/main/java/org/traccar/protocol/SiwiProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SiwiProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/SkypatrolProtocol.java b/src/main/java/org/traccar/protocol/SkypatrolProtocol.java
index 7c6203d86..615ef536d 100644
--- a/src/main/java/org/traccar/protocol/SkypatrolProtocol.java
+++ b/src/main/java/org/traccar/protocol/SkypatrolProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class SkypatrolProtocol extends BaseProtocol {
- public SkypatrolProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public SkypatrolProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new SkypatrolProtocolDecoder(SkypatrolProtocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/SkypatrolProtocolDecoder.java b/src/main/java/org/traccar/protocol/SkypatrolProtocolDecoder.java
index 8aae310bb..6ffcbbe44 100644
--- a/src/main/java/org/traccar/protocol/SkypatrolProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SkypatrolProtocolDecoder.java
@@ -20,8 +20,7 @@ import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.config.Keys;
import org.traccar.helper.BitUtil;
@@ -35,11 +34,15 @@ public class SkypatrolProtocolDecoder extends BaseProtocolDecoder {
private static final Logger LOGGER = LoggerFactory.getLogger(SkypatrolProtocolDecoder.class);
- private final long defaultMask;
+ private long defaultMask;
public SkypatrolProtocolDecoder(Protocol protocol) {
super(protocol);
- defaultMask = Context.getConfig().getInteger(Keys.PROTOCOL_MASK.withPrefix(getProtocolName()));
+ }
+
+ @Override
+ protected void init() {
+ defaultMask = getConfig().getInteger(Keys.PROTOCOL_MASK.withPrefix(getProtocolName()));
}
private static double convertCoordinate(long coordinate) {
diff --git a/src/main/java/org/traccar/protocol/SmartSoleProtocol.java b/src/main/java/org/traccar/protocol/SmartSoleProtocol.java
index bcf43f68b..e4838581a 100644
--- a/src/main/java/org/traccar/protocol/SmartSoleProtocol.java
+++ b/src/main/java/org/traccar/protocol/SmartSoleProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class SmartSoleProtocol extends BaseProtocol {
- public SmartSoleProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public SmartSoleProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '$'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/SmartSoleProtocolDecoder.java b/src/main/java/org/traccar/protocol/SmartSoleProtocolDecoder.java
index 04920c969..7fc38f061 100644
--- a/src/main/java/org/traccar/protocol/SmartSoleProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SmartSoleProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/SmokeyProtocol.java b/src/main/java/org/traccar/protocol/SmokeyProtocol.java
index 482c8347c..0aa2bcfa7 100644
--- a/src/main/java/org/traccar/protocol/SmokeyProtocol.java
+++ b/src/main/java/org/traccar/protocol/SmokeyProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class SmokeyProtocol extends BaseProtocol {
- public SmokeyProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public SmokeyProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new SmokeyProtocolDecoder(SmokeyProtocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/SmokeyProtocolDecoder.java b/src/main/java/org/traccar/protocol/SmokeyProtocolDecoder.java
index 9da52e97a..2244ad289 100644
--- a/src/main/java/org/traccar/protocol/SmokeyProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SmokeyProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java b/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java
index 53a948cdc..e00f27b9b 100644
--- a/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java
+++ b/src/main/java/org/traccar/protocol/SolarPoweredProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class SolarPoweredProtocol extends BaseProtocol {
- public SolarPoweredProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public SolarPoweredProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HuabaoFrameDecoder());
pipeline.addLast(new SolarPoweredProtocolDecoder(SolarPoweredProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java b/src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java
index 9d5dc072f..0432fbd03 100644
--- a/src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SolarPoweredProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/SpotProtocol.java b/src/main/java/org/traccar/protocol/SpotProtocol.java
index bbf0e8d8a..4fc57f177 100644
--- a/src/main/java/org/traccar/protocol/SpotProtocol.java
+++ b/src/main/java/org/traccar/protocol/SpotProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.http.HttpResponseEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class SpotProtocol extends BaseProtocol {
- public SpotProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public SpotProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new HttpResponseEncoder());
pipeline.addLast(new HttpRequestDecoder());
pipeline.addLast(new HttpObjectAggregator(65535));
diff --git a/src/main/java/org/traccar/protocol/SpotProtocolDecoder.java b/src/main/java/org/traccar/protocol/SpotProtocolDecoder.java
index 34417d95f..d493b748d 100644
--- a/src/main/java/org/traccar/protocol/SpotProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SpotProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.channel.Channel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateUtil;
import org.traccar.model.Position;
diff --git a/src/main/java/org/traccar/protocol/StarLinkProtocol.java b/src/main/java/org/traccar/protocol/StarLinkProtocol.java
index 5630722ee..6dcd40fbf 100644
--- a/src/main/java/org/traccar/protocol/StarLinkProtocol.java
+++ b/src/main/java/org/traccar/protocol/StarLinkProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class StarLinkProtocol extends BaseProtocol {
- public StarLinkProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public StarLinkProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java
index 7a6b6f4fe..193005e28 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,8 +17,9 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+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;
import org.traccar.helper.Parser;
@@ -55,17 +56,21 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder {
public StarLinkProtocolDecoder(Protocol protocol) {
super(protocol);
+ }
- setFormat(Context.getConfig().getString(
- getProtocolName() + ".format", "#EDT#,#EID#,#PDT#,#LAT#,#LONG#,#SPD#,#HEAD#,#ODO#,"
+ @Override
+ protected void init() {
+ setFormat(getConfig().getString(
+ Keys.PROTOCOL_FORMAT.withPrefix(getProtocolName()), "#EDT#,#EID#,#PDT#,#LAT#,#LONG#,#SPD#,#HEAD#,#ODO#,"
+ "#IN1#,#IN2#,#IN3#,#IN4#,#OUT1#,#OUT2#,#OUT3#,#OUT4#,#LAC#,#CID#,#VIN#,#VBAT#,#DEST#,#IGN#,#ENG#"));
- setDateFormat(Context.getConfig().getString(getProtocolName() + ".dateFormat", "yyMMddHHmmss"));
+ setDateFormat(getConfig().getString(Keys.PROTOCOL_DATE_FORMAT.withPrefix(getProtocolName()), "yyMMddHHmmss"));
}
public String[] getFormat(long deviceId) {
- return Context.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) {
@@ -73,8 +78,9 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder {
}
public DateFormat getDateFormat(long deviceId) {
- DateFormat dateFormat = new SimpleDateFormat(Context.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;
}
@@ -313,7 +319,7 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder {
}
if (lac != null && cid != null) {
- position.setNetwork(new Network(CellTower.fromLacCid(lac, cid)));
+ position.setNetwork(new Network(CellTower.fromLacCid(getConfig(), lac, cid)));
}
if (event == 20) {
diff --git a/src/main/java/org/traccar/protocol/StarcomProtocol.java b/src/main/java/org/traccar/protocol/StarcomProtocol.java
index 63a6143a6..458220e59 100644
--- a/src/main/java/org/traccar/protocol/StarcomProtocol.java
+++ b/src/main/java/org/traccar/protocol/StarcomProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class StarcomProtocol extends BaseProtocol {
- public StarcomProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public StarcomProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StarcomProtocolDecoder(StarcomProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java
index 5ffddb318..56ab733c8 100644
--- a/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/StarcomProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
diff --git a/src/main/java/org/traccar/protocol/StartekProtocol.java b/src/main/java/org/traccar/protocol/StartekProtocol.java
index 32f1c5a29..550545345 100644
--- a/src/main/java/org/traccar/protocol/StartekProtocol.java
+++ b/src/main/java/org/traccar/protocol/StartekProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2021 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,20 +21,24 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class StartekProtocol extends BaseProtocol {
- public StartekProtocol() {
+ @Inject
+ public StartekProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_OUTPUT_CONTROL,
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
- pipeline.addLast(new LineBasedFrameDecoder(1024));
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new LineBasedFrameDecoder(1100));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StartekProtocolEncoder(StartekProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java
index c1869def2..9c749c8d9 100644
--- a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.Parser;
@@ -72,21 +72,25 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder {
.number("(x+)") // battery
.expression("([^,]+)?") // adc
.groupBegin()
- .text(",")
- .number("d,") // extended
- .expression("([^,]+)?,") // fuel
- .expression("([^,]+)?") // temperature
+ .number(",d+") // extended
+ .expression(",([^,]+)?") // fuel
+ .groupBegin()
+ .expression(",([^,]+)?") // temperature
.groupBegin()
.text(",")
- .number("(d+)|") // rpm
- .number("(d+)|") // engine load
- .number("d+|") // maf flow
- .number("d+|") // intake pressure
- .number("d+|") // intake temperature
- .number("(d+)|") // throttle
- .number("(d+)|") // coolant temperature
- .number("(d+)|") // instant fuel
- .number("(d+)") // fuel level
+ .groupBegin()
+ .number("(d+)?|") // rpm
+ .number("(d+)?|") // engine load
+ .number("(d+)?|") // maf flow
+ .number("(d+)?|") // intake pressure
+ .number("(d+)?|") // intake temperature
+ .number("(d+)?|") // throttle
+ .number("(d+)?|") // coolant temperature
+ .number("(d+)?|") // instant fuel
+ .number("(d+)[%L]").optional() // fuel level
+ .groupEnd("?")
+ .number(",(d+)").optional() // hours
+ .groupEnd("?")
.groupEnd("?")
.groupEnd("?")
.any()
@@ -94,6 +98,8 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder {
private String decodeAlarm(int value) {
switch (value) {
+ case 1:
+ return Position.ALARM_SOS;
case 5:
case 6:
return Position.ALARM_DOOR;
@@ -182,6 +188,7 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder {
int input = parser.nextHexInt();
int output = parser.nextHexInt();
position.set(Position.KEY_IGNITION, BitUtil.check(input, 1));
+ position.set(Position.KEY_DOOR, BitUtil.check(input, 2));
position.set(Position.KEY_INPUT, input);
position.set(Position.KEY_OUTPUT, output);
@@ -217,15 +224,28 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder {
}
}
- if (parser.hasNext(6)) {
+ if (parser.hasNextAny(9)) {
position.set(Position.KEY_RPM, parser.nextInt());
position.set(Position.KEY_ENGINE_LOAD, parser.nextInt());
+ position.set("airFlow", parser.nextInt());
+ position.set("airPressure", parser.nextInt());
+ if (parser.hasNext()) {
+ position.set("airTemp", parser.nextInt() - 40);
+ }
position.set(Position.KEY_THROTTLE, parser.nextInt());
- position.set(Position.KEY_COOLANT_TEMP, parser.nextInt() - 40);
- position.set(Position.KEY_FUEL_CONSUMPTION, parser.nextInt() * 0.1);
+ if (parser.hasNext()) {
+ position.set(Position.KEY_COOLANT_TEMP, parser.nextInt() - 40);
+ }
+ if (parser.hasNext()) {
+ position.set(Position.KEY_FUEL_CONSUMPTION, parser.nextInt() * 0.1);
+ }
position.set(Position.KEY_FUEL_LEVEL, parser.nextInt());
}
+ if (parser.hasNext()) {
+ position.set(Position.KEY_HOURS, parser.nextInt() * 1000L);
+ }
+
return position;
}
diff --git a/src/main/java/org/traccar/protocol/StbProtocol.java b/src/main/java/org/traccar/protocol/StbProtocol.java
index 002ed86c7..0beaed39c 100644
--- a/src/main/java/org/traccar/protocol/StbProtocol.java
+++ b/src/main/java/org/traccar/protocol/StbProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class StbProtocol extends BaseProtocol {
- public StbProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public StbProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new JsonFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/StbProtocolDecoder.java b/src/main/java/org/traccar/protocol/StbProtocolDecoder.java
index cc985d605..c52ab485f 100644
--- a/src/main/java/org/traccar/protocol/StbProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/StbProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2021 - 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,19 +15,16 @@
*/
package org.traccar.protocol;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.core.JsonProcessingException;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.model.Position;
+import org.traccar.session.DeviceSession;
-import javax.json.Json;
-import javax.json.JsonObject;
-import javax.json.JsonValue;
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonValue;
import java.io.StringReader;
import java.net.SocketAddress;
import java.util.Date;
@@ -42,29 +39,13 @@ public class StbProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_PROPERTY = 310;
public static final int MSG_ALARM = 410;
- public static class Response {
- @JsonProperty("msgType")
- private int type;
- @JsonProperty("devId")
- private String deviceId;
- @JsonProperty("result")
- private int result;
- @JsonProperty("txnNo")
- private String transaction;
- }
-
private void sendResponse(
- Channel channel, SocketAddress remoteAddress, int type, String deviceId, JsonObject root)
- throws JsonProcessingException {
-
- Response response = new Response();
- response.type = type + 1;
- response.deviceId = deviceId;
- response.result = 1;
- response.transaction = root.getString("txnNo");
+ Channel channel, SocketAddress remoteAddress, int type, String deviceId, JsonObject root) {
+ String response = String.format(
+ "{ \"msgType\": %d, \"devId\": \"%s\", \"result\": 1, \"txnNo\": \"%s\" }",
+ type + 1, deviceId, root.getString("txnNo"));
if (channel != null) {
- channel.writeAndFlush(new NetworkMessage(
- Context.getObjectMapper().writeValueAsString(response), remoteAddress));
+ channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
}
}
diff --git a/src/main/java/org/traccar/protocol/Stl060Protocol.java b/src/main/java/org/traccar/protocol/Stl060Protocol.java
index 2711e936b..ac23ab3ee 100644
--- a/src/main/java/org/traccar/protocol/Stl060Protocol.java
+++ b/src/main/java/org/traccar/protocol/Stl060Protocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Stl060Protocol extends BaseProtocol {
- public Stl060Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Stl060Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new Stl060FrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/Stl060ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Stl060ProtocolDecoder.java
index 7b0055aa1..dc1fa3ba3 100644
--- a/src/main/java/org/traccar/protocol/Stl060ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Stl060ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/SuntechProtocol.java b/src/main/java/org/traccar/protocol/SuntechProtocol.java
index 199885537..0cc5fc75c 100644
--- a/src/main/java/org/traccar/protocol/SuntechProtocol.java
+++ b/src/main/java/org/traccar/protocol/SuntechProtocol.java
@@ -19,11 +19,15 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class SuntechProtocol extends BaseProtocol {
- public SuntechProtocol() {
+ @Inject
+ public SuntechProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_OUTPUT_CONTROL,
Command.TYPE_REBOOT_DEVICE,
@@ -32,9 +36,9 @@ public class SuntechProtocol extends BaseProtocol {
Command.TYPE_ENGINE_RESUME,
Command.TYPE_ALARM_ARM,
Command.TYPE_ALARM_DISARM);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new SuntechFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new SuntechProtocolEncoder(SuntechProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java
index 8926f427e..86a8bf6fe 100644
--- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java
@@ -20,8 +20,10 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.config.Keys;
+import org.traccar.helper.BufferUtil;
+import org.traccar.helper.model.AttributeUtil;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.DateBuilder;
@@ -41,6 +43,7 @@ import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.TimeZone;
+import java.util.stream.Collectors;
public class SuntechProtocolDecoder extends BaseProtocolDecoder {
@@ -72,8 +75,8 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
}
public int getProtocolType(long deviceId) {
- return Context.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) {
@@ -81,8 +84,8 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
}
public boolean isHbm(long deviceId) {
- return Context.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) {
@@ -90,8 +93,9 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
}
public boolean isIncludeAdc(long deviceId) {
- return Context.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) {
@@ -99,8 +103,9 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
}
public boolean isIncludeRpm(long deviceId) {
- return Context.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) {
@@ -108,8 +113,9 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
}
public boolean isIncludeTemp(long deviceId) {
- return Context.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(
@@ -198,12 +204,16 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
return Position.ALARM_POWER_RESTORED;
case 41:
return Position.ALARM_POWER_CUT;
+ case 42:
+ return Position.ALARM_SOS;
case 46:
return Position.ALARM_ACCELERATION;
case 47:
return Position.ALARM_BRAKING;
case 50:
return Position.ALARM_JAMMING;
+ case 132:
+ return Position.ALARM_DOOR;
default:
return null;
}
@@ -261,18 +271,26 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
index += 1; // collaborative network
}
- DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHH:mm:ss");
- dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- position.setTime(dateFormat.parse(values[index++] + values[index++]));
+ if (values[index].isEmpty()) {
- position.setLatitude(Double.parseDouble(values[index++]));
- position.setLongitude(Double.parseDouble(values[index++]));
- position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++])));
- position.setCourse(Double.parseDouble(values[index++]));
+ getLastLocation(position, null);
- position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++]));
+ } else {
- position.setValid(values[index++].equals("1"));
+ DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHH:mm:ss");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ position.setTime(dateFormat.parse(values[index++] + values[index++]));
+
+ position.setLatitude(Double.parseDouble(values[index++]));
+ position.setLongitude(Double.parseDouble(values[index++]));
+ position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[index++])));
+ position.setCourse(Double.parseDouble(values[index++]));
+
+ position.set(Position.KEY_SATELLITES, Integer.parseInt(values[index++]));
+
+ position.setValid(values[index++].equals("1"));
+
+ }
return position;
}
@@ -371,7 +389,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
}
} else if (attribute.startsWith("GTSL")) {
position.set(Position.KEY_DRIVER_UNIQUE_ID, attribute.split("\\|")[4]);
- } else {
+ } else if (attribute.contains("=")) {
String[] pair = attribute.split("=");
if (pair.length >= 2) {
String value = pair[1].trim();
@@ -394,6 +412,8 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
break;
}
}
+ } else {
+ position.set("serial", attribute.trim());
}
remaining -= attribute.length() + 1;
}
@@ -461,7 +481,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
String type = values[index++];
- if (!type.equals("STT") && !type.equals("ALT") && !type.equals("BLE")) {
+ if (!type.equals("STT") && !type.equals("ALT") && !type.equals("BLE") && !type.equals("RES")) {
return null;
}
@@ -474,6 +494,14 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
position.setDeviceId(deviceSession.getDeviceId());
position.set(Position.KEY_TYPE, type);
+ if (type.equals("RES")) {
+ getLastLocation(position, null);
+ position.set(
+ Position.KEY_RESULT,
+ Arrays.stream(values, index, values.length).collect(Collectors.joining(";")));
+ return position;
+ }
+
int mask;
if (type.equals("BLE")) {
mask = 0b1100000110110;
@@ -563,7 +591,9 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
}
if (BitUtil.check(mask, 17)) {
- position.set(Position.KEY_INPUT, Integer.parseInt(values[index++]));
+ int input = Integer.parseInt(values[index++]);
+ position.set(Position.KEY_IGNITION, BitUtil.check(input, 0));
+ position.set(Position.KEY_INPUT, input);
}
if (BitUtil.check(mask, 18)) {
@@ -572,7 +602,8 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
if (type.equals("ALT")) {
if (BitUtil.check(mask, 19)) {
- position.set("alertId", values[index++]);
+ int alertId = Integer.parseInt(values[index++]);
+ position.set(Position.KEY_ALARM, decodeAlert(alertId));
}
if (BitUtil.check(mask, 20)) {
position.set("alertModifier", values[index++]);
@@ -667,19 +698,11 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
}
if (BitUtil.check(mask, 11)) {
- long value = buf.readUnsignedInt();
- if (BitUtil.check(value, 31)) {
- value = -BitUtil.to(value, 31);
- }
- position.setLatitude(value / 1000000.0);
+ position.setLatitude(BufferUtil.readSignedMagnitudeInt(buf) / 1000000.0);
}
if (BitUtil.check(mask, 12)) {
- long value = buf.readUnsignedInt();
- if (BitUtil.check(value, 31)) {
- value = -BitUtil.to(value, 31);
- }
- position.setLongitude(value / 1000000.0);
+ position.setLongitude(BufferUtil.readSignedMagnitudeInt(buf) / 1000000.0);
}
if (BitUtil.check(mask, 13)) {
@@ -841,7 +864,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
} else {
- String[] values = buf.toString(StandardCharsets.US_ASCII).split(";");
+ String[] values = buf.toString(StandardCharsets.US_ASCII).split(";", -1);
prefix = values[0];
if (prefix.equals("CRR")) {
diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java
index 597acaae8..a4faacf13 100644
--- a/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java
@@ -45,13 +45,13 @@ public class SuntechProtocolEncoder extends StringProtocolEncoder {
}
if (universal) {
- return encodeUniversalCommand(channel, command);
+ return encodeUniversalCommand(command);
} else {
- return encodeLegacyCommand(channel, prefix, command);
+ return encodeLegacyCommand(prefix, command);
}
}
- protected Object encodeUniversalCommand(Channel channel, Command command) {
+ protected Object encodeUniversalCommand(Command command) {
switch (command.getType()) {
case Command.TYPE_REBOOT_DEVICE:
return formatCommand(command, "CMD;%s;03;03\r", Command.KEY_UNIQUE_ID);
@@ -59,23 +59,23 @@ public class SuntechProtocolEncoder extends StringProtocolEncoder {
return formatCommand(command, "CMD;%s;03;01\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_OUTPUT_CONTROL:
if (command.getAttributes().get(Command.KEY_DATA).equals("1")) {
- switch (command.getString(Command.KEY_INDEX)) {
- case "1":
+ switch (command.getInteger(Command.KEY_INDEX)) {
+ case 1:
return formatCommand(command, "CMD;%s;04;01\r", Command.KEY_UNIQUE_ID);
- case "2":
+ case 2:
return formatCommand(command, "CMD;%s;04;03\r", Command.KEY_UNIQUE_ID);
- case "3":
+ case 3:
return formatCommand(command, "CMD;%s;04;09\r", Command.KEY_UNIQUE_ID);
default:
return null;
}
} else {
- switch (command.getString(Command.KEY_INDEX)) {
- case "1":
+ switch (command.getInteger(Command.KEY_INDEX)) {
+ case 1:
return formatCommand(command, "CMD;%s;04;02\r", Command.KEY_UNIQUE_ID);
- case "2":
+ case 2:
return formatCommand(command, "CMD;%s;04;04\r", Command.KEY_UNIQUE_ID);
- case "3":
+ case 3:
return formatCommand(command, "CMD;%s;04;10\r", Command.KEY_UNIQUE_ID);
default:
return null;
@@ -84,7 +84,7 @@ public class SuntechProtocolEncoder extends StringProtocolEncoder {
case Command.TYPE_ENGINE_STOP:
return formatCommand(command, "CMD;%s;04;01\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_ENGINE_RESUME:
- return formatCommand(command, "CMD;%s;02;02\r", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "CMD;%s;04;02\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_ALARM_ARM:
return formatCommand(command, "CMD;%s;04;03\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_ALARM_DISARM:
@@ -94,12 +94,12 @@ public class SuntechProtocolEncoder extends StringProtocolEncoder {
}
}
- protected Object encodeLegacyCommand(Channel channel, String prefix, Command command) {
+ protected Object encodeLegacyCommand(String prefix, Command command) {
switch (command.getType()) {
case Command.TYPE_REBOOT_DEVICE:
return formatCommand(command, prefix + "CMD;%s;02;Reboot\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_POSITION_SINGLE:
- return formatCommand(command, prefix + "CMD;%s;02;\r", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, prefix + "CMD;%s;02;StatusReq\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_OUTPUT_CONTROL:
if (command.getAttributes().get(Command.KEY_DATA).equals("1")) {
return formatCommand(command, prefix + "CMD;%s;02;Enable%s\r",
diff --git a/src/main/java/org/traccar/protocol/SupermateProtocol.java b/src/main/java/org/traccar/protocol/SupermateProtocol.java
index 46625ddc7..064f12b4b 100644
--- a/src/main/java/org/traccar/protocol/SupermateProtocol.java
+++ b/src/main/java/org/traccar/protocol/SupermateProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class SupermateProtocol extends BaseProtocol {
- public SupermateProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public SupermateProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "#"));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/SupermateProtocolDecoder.java b/src/main/java/org/traccar/protocol/SupermateProtocolDecoder.java
index 40a25bb91..f53f0f598 100644
--- a/src/main/java/org/traccar/protocol/SupermateProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SupermateProtocolDecoder.java
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/SviasProtocol.java b/src/main/java/org/traccar/protocol/SviasProtocol.java
index accfa173f..a903d503c 100644
--- a/src/main/java/org/traccar/protocol/SviasProtocol.java
+++ b/src/main/java/org/traccar/protocol/SviasProtocol.java
@@ -21,12 +21,15 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
-
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class SviasProtocol extends BaseProtocol {
- public SviasProtocol() {
+ @Inject
+ public SviasProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_POSITION_SINGLE,
@@ -36,9 +39,9 @@ public class SviasProtocol extends BaseProtocol {
Command.TYPE_ALARM_ARM,
Command.TYPE_ALARM_DISARM,
Command.TYPE_ALARM_REMOVE);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "]"));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/SviasProtocolDecoder.java b/src/main/java/org/traccar/protocol/SviasProtocolDecoder.java
index 7e783f6cd..d7b126167 100644
--- a/src/main/java/org/traccar/protocol/SviasProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SviasProtocolDecoder.java
@@ -24,7 +24,7 @@ import org.traccar.helper.PatternBuilder;
import java.net.SocketAddress;
import java.util.regex.Pattern;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.helper.Parser;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
diff --git a/src/main/java/org/traccar/protocol/SwiftechProtocol.java b/src/main/java/org/traccar/protocol/SwiftechProtocol.java
index 5e2597b93..d5fa5c5d3 100644
--- a/src/main/java/org/traccar/protocol/SwiftechProtocol.java
+++ b/src/main/java/org/traccar/protocol/SwiftechProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class SwiftechProtocol extends BaseProtocol {
- public SwiftechProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public SwiftechProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/SwiftechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SwiftechProtocolDecoder.java
index 8d0b31c8f..b1cff8b64 100644
--- a/src/main/java/org/traccar/protocol/SwiftechProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SwiftechProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/T55Protocol.java b/src/main/java/org/traccar/protocol/T55Protocol.java
index f5ec19094..e76959fea 100644
--- a/src/main/java/org/traccar/protocol/T55Protocol.java
+++ b/src/main/java/org/traccar/protocol/T55Protocol.java
@@ -21,22 +21,26 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class T55Protocol extends BaseProtocol {
- public T55Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public T55Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new T55ProtocolDecoder(T55Protocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new T55ProtocolDecoder(T55Protocol.this));
diff --git a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java
index 230d29216..b18359b3f 100644
--- a/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/T55ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,8 +17,9 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.AttributeUtil;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
@@ -27,6 +28,7 @@ import org.traccar.helper.PatternBuilder;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
+import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.channels.DatagramChannel;
import java.util.Date;
@@ -124,15 +126,53 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
.expression("([01])") // ignition
.compile();
+ private static final Pattern PATTERN_PUBX = new PatternBuilder()
+ .text("$PUBX,")
+ .number("(d+),") // index
+ .number("(dd)(dd)(dd).d+,") // time (hhmmss)
+ .number("(dd)(dd.d+),([NS]),") // latitude
+ .number("(ddd)(dd.d+),([EW]),") // longitude
+ .number("(-?d+.d+),") // altitude
+ .expression("(..),") // status
+ .number("(d+.d+),") // horizontal accuracy
+ .number("d+.d+,") // vertical accuracy
+ .number("(d+.d+),") // speed
+ .number("(d+.d+),") // course
+ .number("-?d+.d+,") // vertical velocity
+ .expression("[^,]*,") // corrections age
+ .number("(d+.d+),") // hdop
+ .number("(d+.d+),") // vdop
+ .number("d+.d+,") // tdop
+ .number("(d+),") // satellites
+ .number("(d+),") // device id
+ .number("d+")
+ .text("*")
+ .number("xx") // checksum
+ .compile();
+
+ private static final Pattern PATTERN_GPTXT = new PatternBuilder()
+ .text("$GPTXT,")
+ .text("NET,")
+ .number("(d+),") // device id
+ .expression("([^,]+),") // network operator
+ .number("(-d+),") // rssi
+ .number("(d+) ") // mcc
+ .number("(d+)") // mnc
+ .text("*")
+ .number("xx") // checksum
+ .compile();
+
private Position position = null;
private Position decodeGprmc(
DeviceSession deviceSession, String sentence, SocketAddress remoteAddress, Channel channel) {
- if (deviceSession != null && channel != null && !(channel instanceof DatagramChannel)
- && Context.getIdentityManager().lookupAttributeBoolean(
- deviceSession.getDeviceId(), getProtocolName() + ".ack", false, false, true)) {
- channel.writeAndFlush(new NetworkMessage("OK1\r\n", remoteAddress));
+ if (deviceSession != null && channel != null && !(channel instanceof DatagramChannel)) {
+ boolean ack = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_ACK.withPrefix(getProtocolName()), deviceSession.getDeviceId());
+ if (ack) {
+ channel.writeAndFlush(new NetworkMessage("OK1\r\n", remoteAddress));
+ }
}
Parser parser = new Parser(PATTERN_GPRMC, sentence);
@@ -300,11 +340,69 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private Position decodeGptxt(Channel channel, SocketAddress remoteAddress, String sentence) {
+
+ Parser parser = new Parser(PATTERN_GPTXT, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ getLastLocation(position, null);
+
+ position.set(Position.KEY_OPERATOR, parser.next());
+ position.set(Position.KEY_RSSI, parser.nextInt());
+ position.set("mcc", parser.nextInt());
+ position.set("mnc", parser.nextInt());
+
+ return position;
+ }
+
+ private Position decodePubx(Channel channel, SocketAddress remoteAddress, String sentence) {
+
+ Parser parser = new Parser(PATTERN_PUBX, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+
+ position.set(Position.KEY_INDEX, parser.nextInt());
+
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.HMS));
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+ position.setAltitude(parser.nextDouble());
+ position.setValid(!parser.next().equals("NF"));
+ position.setAccuracy(parser.nextDouble());
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
+
+ position.set(Position.KEY_HDOP, parser.nextDouble());
+ position.set(Position.KEY_VDOP, parser.nextDouble());
+ position.set(Position.KEY_SATELLITES, parser.nextInt());
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession != null) {
+ position.setDeviceId(deviceSession.getDeviceId());
+ return position;
+ }
+
+ return null;
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- String sentence = (String) msg;
+ String sentence = ((String) msg).trim();
DeviceSession deviceSession;
@@ -320,6 +418,10 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
sentence = sentence.substring(index);
} else {
deviceSession = getDeviceSession(channel, remoteAddress);
+ if (deviceSession == null && remoteAddress instanceof InetSocketAddress) {
+ String host = ((InetSocketAddress) remoteAddress).getHostString();
+ deviceSession = getDeviceSession(channel, remoteAddress, host);
+ }
}
if (sentence.startsWith("$PGID")) {
@@ -354,6 +456,10 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
return decodeGpiop(deviceSession, sentence);
} else if (sentence.startsWith("QZE")) {
return decodeQze(channel, remoteAddress, sentence);
+ } else if (sentence.startsWith("$PUBX")) {
+ return decodePubx(channel, remoteAddress, sentence);
+ } else if (sentence.startsWith("$GPTXT")) {
+ return decodeGptxt(channel, remoteAddress, sentence);
}
return null;
diff --git a/src/main/java/org/traccar/protocol/T57Protocol.java b/src/main/java/org/traccar/protocol/T57Protocol.java
index f67f82318..e6ef4ccc9 100644
--- a/src/main/java/org/traccar/protocol/T57Protocol.java
+++ b/src/main/java/org/traccar/protocol/T57Protocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class T57Protocol extends BaseProtocol {
- public T57Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public T57Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new T57FrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/T57ProtocolDecoder.java b/src/main/java/org/traccar/protocol/T57ProtocolDecoder.java
index 2a3cca3e4..d9fd1c8cf 100644
--- a/src/main/java/org/traccar/protocol/T57ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/T57ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/T622IridiumProtocol.java b/src/main/java/org/traccar/protocol/T622IridiumProtocol.java
new file mode 100644
index 000000000..22efa38a8
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/T622IridiumProtocol.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
+
+public class T622IridiumProtocol extends BaseProtocol {
+
+ @Inject
+ public T622IridiumProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 1, 2));
+ pipeline.addLast(new T622IridiumProtocolDecoder(T622IridiumProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java b/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java
new file mode 100644
index 000000000..9e64ec9be
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/T622IridiumProtocolDecoder.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.Protocol;
+import org.traccar.config.Keys;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.helper.model.AttributeUtil;
+import org.traccar.model.Position;
+import org.traccar.session.DeviceSession;
+
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class T622IridiumProtocolDecoder extends BaseProtocolDecoder {
+
+ private String format;
+
+ public T622IridiumProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ public List<Integer> getParameters(long deviceId) {
+ String value = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_FORMAT.withPrefix(getProtocolName()), deviceId);
+ return Arrays.stream((value != null ? value : format).split(","))
+ .map(s -> Integer.parseInt(s, 16))
+ .collect(Collectors.toList());
+ }
+
+ public void setFormat(String format) {
+ this.format = format;
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ByteBuf buf = (ByteBuf) msg;
+
+ buf.readUnsignedByte(); // protocol revision
+ buf.readUnsignedShort(); // length
+ buf.readUnsignedByte(); // header indicator
+ buf.readUnsignedShort(); // header length
+ buf.readUnsignedInt(); // reference
+
+ String imei = buf.readCharSequence(15, StandardCharsets.US_ASCII).toString();
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ buf.readUnsignedByte(); // session status
+ buf.readUnsignedShort(); // originator index
+ buf.readUnsignedShort(); // transfer index
+ buf.readUnsignedInt(); // session time
+ buf.readUnsignedByte(); // payload indicator
+ buf.readUnsignedShort(); // payload length
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ List<Integer> parameters = getParameters(deviceSession.getDeviceId());
+
+ for (int parameter : parameters) {
+ switch (parameter) {
+ case 0x01:
+ position.set(Position.KEY_EVENT, buf.readUnsignedByte());
+ break;
+ case 0x02:
+ position.setLatitude(buf.readIntLE() / 1000000.0);
+ break;
+ case 0x03:
+ position.setLongitude(buf.readIntLE() / 1000000.0);
+ break;
+ case 0x04:
+ position.setTime(new Date((buf.readUnsignedIntLE() + 946684800) * 1000));
+ break;
+ case 0x05:
+ position.setValid(buf.readUnsignedByte() > 0);
+ break;
+ case 0x06:
+ position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
+ break;
+ case 0x07:
+ position.set(Position.KEY_RSSI, buf.readUnsignedByte());
+ break;
+ case 0x08:
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE()));
+ break;
+ case 0x09:
+ position.setCourse(buf.readUnsignedShortLE());
+ break;
+ case 0x0A:
+ position.set(Position.KEY_HDOP, buf.readUnsignedByte() * 0.1);
+ break;
+ case 0x0B:
+ position.setAltitude(buf.readShortLE());
+ break;
+ case 0x0C:
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedIntLE());
+ break;
+ case 0x0D:
+ position.set(Position.KEY_HOURS, buf.readUnsignedIntLE() * 1000);
+ break;
+ case 0x14:
+ position.set(Position.KEY_OUTPUT, buf.readUnsignedByte());
+ break;
+ case 0x15:
+ position.set(Position.KEY_INPUT, buf.readUnsignedByte());
+ break;
+ case 0x19:
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01);
+ break;
+ case 0x1A:
+ position.set(Position.KEY_POWER, buf.readUnsignedShortLE() * 0.01);
+ break;
+ case 0x1B:
+ buf.readUnsignedByte(); // geofence
+ break;
+ default:
+ break;
+ }
+ }
+
+ return position;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/T800xProtocol.java b/src/main/java/org/traccar/protocol/T800xProtocol.java
index 8b91265cb..f50f22a18 100644
--- a/src/main/java/org/traccar/protocol/T800xProtocol.java
+++ b/src/main/java/org/traccar/protocol/T800xProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -19,21 +19,32 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class T800xProtocol extends BaseProtocol {
- public T800xProtocol() {
+ @Inject
+ public T800xProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2, -5, 0));
pipeline.addLast(new T800xProtocolEncoder(T800xProtocol.this));
pipeline.addLast(new T800xProtocolDecoder(T800xProtocol.this));
}
});
+ addServer(new TrackerServer(config, getName(), true) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new T800xProtocolEncoder(T800xProtocol.this));
+ pipeline.addLast(new T800xProtocolDecoder(T800xProtocol.this));
+ }
+ });
}
}
diff --git a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java
index d554c2999..4ddea730c 100644
--- a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,9 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.AttributeUtil;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BcdUtil;
@@ -58,6 +60,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_DRIVER_BEHAVIOR_1 = 0x05; // 0x2626
public static final int MSG_DRIVER_BEHAVIOR_2 = 0x06; // 0x2626
public static final int MSG_BLE = 0x10;
+ public static final int MSG_NETWORK_2 = 0x11;
public static final int MSG_GPS_2 = 0x13;
public static final int MSG_ALARM_2 = 0x14;
public static final int MSG_COMMAND = 0x81;
@@ -167,7 +170,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder {
return decodePosition(channel, deviceSession, buf, type, index, imei);
- } else if (type == MSG_NETWORK && header == 0x2727) {
+ } else if (type == MSG_NETWORK && header == 0x2727 || type == MSG_NETWORK_2) {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
@@ -397,6 +400,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder {
int alarm = buf.readUnsignedByte();
position.set(Position.KEY_ALARM, header != 0x2727 ? decodeAlarm1(alarm) : decodeAlarm2(alarm));
+ position.set("alarmCode", alarm);
if (header != 0x2727) {
@@ -467,6 +471,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder {
int inputStatus = buf.readUnsignedShort();
position.set(Position.KEY_IGNITION, BitUtil.check(inputStatus, 2));
position.set(Position.KEY_RSSI, BitUtil.between(inputStatus, 4, 11));
+ position.set(Position.KEY_INPUT, inputStatus);
buf.readUnsignedShort(); // ignition on upload interval
buf.readUnsignedInt(); // ignition off upload interval
@@ -510,7 +515,9 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder {
}
}
- if (type == MSG_ALARM || type == MSG_ALARM_2) {
+ boolean acknowledgement = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_ACK.withPrefix(getProtocolName()), deviceSession.getDeviceId());
+ if (acknowledgement || type == MSG_ALARM || type == MSG_ALARM_2) {
sendResponse(channel, header, type, index, imei, alarm);
}
diff --git a/src/main/java/org/traccar/protocol/TaipPrefixEncoder.java b/src/main/java/org/traccar/protocol/TaipPrefixEncoder.java
index 02c111b01..48419af2a 100644
--- a/src/main/java/org/traccar/protocol/TaipPrefixEncoder.java
+++ b/src/main/java/org/traccar/protocol/TaipPrefixEncoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2021 - 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,13 +15,14 @@
*/
package org.traccar.protocol;
+import com.google.inject.Inject;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
-import org.traccar.Context;
import org.traccar.Protocol;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import java.util.List;
@@ -30,14 +31,20 @@ import java.util.List;
public class TaipPrefixEncoder extends MessageToMessageEncoder<ByteBuf> {
private final Protocol protocol;
+ private Config config;
public TaipPrefixEncoder(Protocol protocol) {
this.protocol = protocol;
}
+ @Inject
+ public void setConfig(Config config) {
+ this.config = config;
+ }
+
@Override
- protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
- if (Context.getConfig().getBoolean(Keys.PROTOCOL_PREFIX.withPrefix(protocol.getName()))) {
+ protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) {
+ if (config.getBoolean(Keys.PROTOCOL_PREFIX.withPrefix(protocol.getName()))) {
out.add(Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(new byte[] {0x20, 0x20, 0x06, 0x00}), msg.retain()));
} else {
out.add(msg.retain());
diff --git a/src/main/java/org/traccar/protocol/TaipProtocol.java b/src/main/java/org/traccar/protocol/TaipProtocol.java
index 0966cfd7c..71ab485ca 100644
--- a/src/main/java/org/traccar/protocol/TaipProtocol.java
+++ b/src/main/java/org/traccar/protocol/TaipProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TaipProtocol extends BaseProtocol {
- public TaipProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TaipProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '<'));
pipeline.addLast(new TaipPrefixEncoder(TaipProtocol.this));
pipeline.addLast(new StringDecoder());
@@ -35,9 +39,9 @@ public class TaipProtocol extends BaseProtocol {
pipeline.addLast(new TaipProtocolDecoder(TaipProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new TaipPrefixEncoder(TaipProtocol.this));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java
index ec0ce1931..787ed1599 100644
--- a/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TaipProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -26,7 +26,6 @@ import org.traccar.helper.DateBuilder;
import org.traccar.helper.DateUtil;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
-import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
import java.net.SocketAddress;
@@ -192,7 +191,7 @@ public class TaipProtocolDecoder extends BaseProtocolDecoder {
position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG_MIN));
}
- position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble(0)));
+ position.setSpeed(convertSpeed(parser.nextDouble(0), "mph"));
position.setCourse(parser.nextDouble(0));
if (parser.hasNext(2)) {
diff --git a/src/main/java/org/traccar/protocol/TechTltProtocol.java b/src/main/java/org/traccar/protocol/TechTltProtocol.java
index 0cffb452d..a4a7460b0 100644
--- a/src/main/java/org/traccar/protocol/TechTltProtocol.java
+++ b/src/main/java/org/traccar/protocol/TechTltProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TechTltProtocol extends BaseProtocol {
- public TechTltProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public TechTltProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new TechTltProtocolDecoder(TechTltProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/TechTltProtocolDecoder.java b/src/main/java/org/traccar/protocol/TechTltProtocolDecoder.java
index 17f5c80fa..94efacc63 100644
--- a/src/main/java/org/traccar/protocol/TechTltProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TechTltProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
@@ -110,7 +110,7 @@ public class TechTltProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_SATELLITES, parser.nextInt());
- position.setNetwork(new Network(CellTower.fromLacCid(parser.nextInt(), parser.nextInt())));
+ position.setNetwork(new Network(CellTower.fromLacCid(getConfig(), parser.nextInt(), parser.nextInt())));
return position;
}
diff --git a/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java b/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java
index a217ea738..f0828a99e 100644
--- a/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java
+++ b/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TechtoCruzProtocol extends BaseProtocol {
- public TechtoCruzProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TechtoCruzProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new TechtoCruzFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/TechtoCruzProtocolDecoder.java b/src/main/java/org/traccar/protocol/TechtoCruzProtocolDecoder.java
index 6b9f0edb6..09efcb7d4 100644
--- a/src/main/java/org/traccar/protocol/TechtoCruzProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TechtoCruzProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/TekProtocol.java b/src/main/java/org/traccar/protocol/TekProtocol.java
index c1d78e6f5..56714041b 100644
--- a/src/main/java/org/traccar/protocol/TekProtocol.java
+++ b/src/main/java/org/traccar/protocol/TekProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TekProtocol extends BaseProtocol {
- public TekProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TekProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new TekFrameDecoder());
pipeline.addLast(new TekProtocolDecoder(TekProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/TekProtocolDecoder.java b/src/main/java/org/traccar/protocol/TekProtocolDecoder.java
index 33ff51d2d..819c7e819 100644
--- a/src/main/java/org/traccar/protocol/TekProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TekProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/TelemaxProtocol.java b/src/main/java/org/traccar/protocol/TelemaxProtocol.java
index 838da9df1..792a5b176 100644
--- a/src/main/java/org/traccar/protocol/TelemaxProtocol.java
+++ b/src/main/java/org/traccar/protocol/TelemaxProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TelemaxProtocol extends BaseProtocol {
- public TelemaxProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TelemaxProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/TelemaxProtocolDecoder.java b/src/main/java/org/traccar/protocol/TelemaxProtocolDecoder.java
index 9369ab101..f6f6f5379 100644
--- a/src/main/java/org/traccar/protocol/TelemaxProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TelemaxProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.model.Position;
diff --git a/src/main/java/org/traccar/protocol/TelicProtocol.java b/src/main/java/org/traccar/protocol/TelicProtocol.java
index 991befa19..fc5bdf0d1 100644
--- a/src/main/java/org/traccar/protocol/TelicProtocol.java
+++ b/src/main/java/org/traccar/protocol/TelicProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TelicProtocol extends BaseProtocol {
- public TelicProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TelicProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new TelicFrameDecoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java b/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java
index a4f9e2989..9681dc565 100644
--- a/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TelicProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java
index c30fee6e3..3a0962584 100644
--- a/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java
+++ b/src/main/java/org/traccar/protocol/TeltonikaFrameDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 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.
@@ -30,7 +30,7 @@ public class TeltonikaFrameDecoder extends BaseFrameDecoder {
ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception {
while (buf.isReadable() && buf.getByte(buf.readerIndex()) == (byte) 0xff) {
- buf.skipBytes(1);
+ return buf.readRetainedSlice(1);
}
if (buf.readableBytes() < MESSAGE_MINIMUM_LENGTH) {
diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocol.java b/src/main/java/org/traccar/protocol/TeltonikaProtocol.java
index 5817b86be..f2d610251 100644
--- a/src/main/java/org/traccar/protocol/TeltonikaProtocol.java
+++ b/src/main/java/org/traccar/protocol/TeltonikaProtocol.java
@@ -18,24 +18,28 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class TeltonikaProtocol extends BaseProtocol {
- public TeltonikaProtocol() {
+ @Inject
+ public TeltonikaProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new TeltonikaFrameDecoder());
pipeline.addLast(new TeltonikaProtocolEncoder(TeltonikaProtocol.this));
pipeline.addLast(new TeltonikaProtocolDecoder(TeltonikaProtocol.this, false));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new TeltonikaProtocolEncoder(TeltonikaProtocol.this));
pipeline.addLast(new TeltonikaProtocolDecoder(TeltonikaProtocol.this, true));
}
diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java
index f83a49941..e888642b4 100644
--- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,8 +20,9 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.helper.BufferUtil;
+import org.traccar.model.Device;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.config.Keys;
@@ -39,11 +40,15 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.function.BiConsumer;
public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
private static final int IMAGE_PACKET_MAX = 2048;
+ private static final Map<Integer, Map<Set<String>, BiConsumer<Position, ByteBuf>>> PARAMETERS = new HashMap<>();
+
private final boolean connectionless;
private boolean extended;
private final Map<Long, ByteBuf> photos = new HashMap<>();
@@ -55,7 +60,11 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
public TeltonikaProtocolDecoder(Protocol protocol, boolean connectionless) {
super(protocol);
this.connectionless = connectionless;
- this.extended = Context.getConfig().getBoolean(Keys.PROTOCOL_EXTENDED.withPrefix(getProtocolName()));
+ }
+
+ @Override
+ protected void init() {
+ this.extended = getConfig().getBoolean(Keys.PROTOCOL_EXTENDED.withPrefix(getProtocolName()));
}
private void parseIdentification(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
@@ -104,19 +113,8 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
}
}
- private boolean isPrintable(ByteBuf buf, int length) {
- boolean printable = true;
- for (int i = 0; i < length; i++) {
- byte b = buf.getByte(buf.readerIndex() + i);
- if (b < 32 && b != '\r' && b != '\n') {
- printable = false;
- break;
- }
- }
- return printable;
- }
-
- private void decodeSerial(Channel channel, SocketAddress remoteAddress, Position position, ByteBuf buf) {
+ private void decodeSerial(
+ Channel channel, SocketAddress remoteAddress, DeviceSession deviceSession, Position position, ByteBuf buf) {
getLastLocation(position, null);
@@ -145,10 +143,9 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
channel, remoteAddress, photoId,
photo.writerIndex(), Math.min(IMAGE_PACKET_MAX, photo.writableBytes()));
} else {
- String uniqueId = Context.getIdentityManager().getById(position.getDeviceId()).getUniqueId();
photos.remove(photoId);
try {
- position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(uniqueId, photo, "jpg"));
+ position.set(Position.KEY_IMAGE, writeMediaFile(deviceSession.getUniqueId(), photo, "jpg"));
} finally {
photo.release();
}
@@ -161,7 +158,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_TYPE, type);
int length = buf.readInt();
- if (isPrintable(buf, length)) {
+ if (BufferUtil.isPrintable(buf, length)) {
String data = buf.readSlice(length).toString(StandardCharsets.US_ASCII).trim();
if (data.startsWith("UUUUww") && data.endsWith("SSS")) {
String[] values = data.substring(6, data.length() - 4).split(";");
@@ -181,191 +178,229 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
}
}
- private long readValue(ByteBuf buf, int length, boolean signed) {
+ private long readValue(ByteBuf buf, int length) {
switch (length) {
case 1:
- return signed ? buf.readByte() : buf.readUnsignedByte();
+ return buf.readUnsignedByte();
case 2:
- return signed ? buf.readShort() : buf.readUnsignedShort();
+ return buf.readUnsignedShort();
case 4:
- return signed ? buf.readInt() : buf.readUnsignedInt();
+ return buf.readUnsignedInt();
default:
return buf.readLong();
}
}
- private void decodeOtherParameter(Position position, int id, ByteBuf buf, int length) {
- switch (id) {
- case 1:
- case 2:
- case 3:
- case 4:
- position.set("di" + id, readValue(buf, length, false));
- break;
- case 9:
- position.set(Position.PREFIX_ADC + 1, readValue(buf, length, false));
- break;
- case 10:
- position.set(Position.PREFIX_ADC + 2, readValue(buf, length, false));
- break;
- case 16:
- position.set(Position.KEY_ODOMETER, readValue(buf, length, false));
- break;
- case 17:
- position.set("axisX", readValue(buf, length, true));
- break;
- case 18:
- position.set("axisY", readValue(buf, length, true));
- break;
- case 19:
- position.set("axisZ", readValue(buf, length, true));
- break;
- case 21:
- position.set(Position.KEY_RSSI, readValue(buf, length, false));
- break;
- case 25:
- case 26:
- case 27:
- case 28:
- position.set(Position.PREFIX_TEMP + (id - 24 + 4), readValue(buf, length, true) * 0.1);
- break;
- case 66:
- position.set(Position.KEY_POWER, readValue(buf, length, false) * 0.001);
- break;
- case 67:
- position.set(Position.KEY_BATTERY, readValue(buf, length, false) * 0.001);
- break;
- case 72:
- case 73:
- case 74:
- position.set(Position.PREFIX_TEMP + (id - 71), readValue(buf, length, true) * 0.1);
- break;
- case 78:
- long driverUniqueId = readValue(buf, length, false);
- if (driverUniqueId != 0) {
- position.set(Position.KEY_DRIVER_UNIQUE_ID, String.format("%016X", driverUniqueId));
- }
- break;
- case 80:
- position.set("workMode", readValue(buf, length, false));
- break;
- case 90:
- position.set(Position.KEY_DOOR, readValue(buf, length, false));
- break;
- case 115:
- position.set(Position.KEY_COOLANT_TEMP, readValue(buf, length, true) * 0.1);
- break;
- case 179:
- position.set(Position.PREFIX_OUT + 1, readValue(buf, length, false) == 1);
- break;
- case 180:
- position.set(Position.PREFIX_OUT + 2, readValue(buf, length, false) == 1);
- break;
- case 181:
- position.set(Position.KEY_PDOP, readValue(buf, length, false) * 0.1);
- break;
- case 182:
- position.set(Position.KEY_HDOP, readValue(buf, length, false) * 0.1);
- break;
- case 199:
- position.set(Position.KEY_ODOMETER_TRIP, readValue(buf, length, false));
- break;
- case 236:
- if (readValue(buf, length, false) == 1) {
- position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
- }
- break;
- case 239:
- position.set(Position.KEY_IGNITION, readValue(buf, length, false) == 1);
- break;
- case 240:
- position.set(Position.KEY_MOTION, readValue(buf, length, false) == 1);
- break;
- case 241:
- position.set(Position.KEY_OPERATOR, readValue(buf, length, false));
- break;
- case 253:
- switch ((int) readValue(buf, length, false)) {
- case 1:
- position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
- break;
- case 2:
- position.set(Position.KEY_ALARM, Position.ALARM_BRAKING);
- break;
- case 3:
- position.set(Position.KEY_ALARM, Position.ALARM_CORNERING);
- break;
- default:
- break;
- }
- break;
- default:
- position.set(Position.PREFIX_IO + id, readValue(buf, length, false));
- break;
- }
+ private static void register(int id, Set<String> models, BiConsumer<Position, ByteBuf> handler) {
+ PARAMETERS.computeIfAbsent(id, key -> new HashMap<>()).put(models, handler);
+ }
+
+ static {
+ var fmbXXX = Set.of(
+ "FMB001", "FMB010", "FMB002", "FMB020", "FMB003", "FMB110", "FMB120", "FMB122", "FMB125", "FMB130",
+ "FMB140", "FMU125", "FMB900", "FMB920", "FMB962", "FMB964", "FM3001", "FMB202", "FMB204", "FMB206",
+ "FMT100", "MTB100", "FMP100", "MSP500");
+
+ register(1, null, (p, b) -> p.set(Position.PREFIX_IN + 1, b.readUnsignedByte() > 0));
+ register(2, null, (p, b) -> p.set(Position.PREFIX_IN + 2, b.readUnsignedByte() > 0));
+ register(3, null, (p, b) -> p.set(Position.PREFIX_IN + 3, b.readUnsignedByte() > 0));
+ register(4, null, (p, b) -> p.set(Position.PREFIX_IN + 4, b.readUnsignedByte() > 0));
+ register(9, fmbXXX, (p, b) -> p.set(Position.PREFIX_ADC + 1, b.readUnsignedShort() * 0.001));
+ register(10, fmbXXX, (p, b) -> p.set(Position.PREFIX_ADC + 2, b.readUnsignedShort() * 0.001));
+ register(11, fmbXXX, (p, b) -> p.set(Position.KEY_ICCID, String.valueOf(b.readLong())));
+ register(12, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_USED, b.readUnsignedInt() * 0.001));
+ register(13, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_CONSUMPTION, b.readUnsignedShort() * 0.01));
+ register(16, null, (p, b) -> p.set(Position.KEY_ODOMETER, b.readUnsignedInt()));
+ register(17, null, (p, b) -> p.set("axisX", b.readShort()));
+ register(18, null, (p, b) -> p.set("axisY", b.readShort()));
+ register(19, null, (p, b) -> p.set("axisZ", b.readShort()));
+ register(21, null, (p, b) -> p.set(Position.KEY_RSSI, b.readUnsignedByte()));
+ register(24, fmbXXX, (p, b) -> p.setSpeed(UnitsConverter.knotsFromKph(b.readUnsignedShort())));
+ register(25, null, (p, b) -> p.set("bleTemp1", b.readShort() * 0.01));
+ register(26, null, (p, b) -> p.set("bleTemp2", b.readShort() * 0.01));
+ register(27, null, (p, b) -> p.set("bleTemp3", b.readShort() * 0.01));
+ register(28, null, (p, b) -> p.set("bleTemp4", b.readShort() * 0.01));
+ register(30, fmbXXX, (p, b) -> p.set("faultCount", b.readUnsignedByte()));
+ register(32, fmbXXX, (p, b) -> p.set(Position.KEY_COOLANT_TEMP, b.readByte()));
+ register(66, null, (p, b) -> p.set(Position.KEY_POWER, b.readUnsignedShort() * 0.001));
+ register(67, null, (p, b) -> p.set(Position.KEY_BATTERY, b.readUnsignedShort() * 0.001));
+ register(68, fmbXXX, (p, b) -> p.set("batteryCurrent", b.readUnsignedShort() * 0.001));
+ register(72, fmbXXX, (p, b) -> p.set(Position.PREFIX_TEMP + 1, b.readInt() * 0.1));
+ register(73, fmbXXX, (p, b) -> p.set(Position.PREFIX_TEMP + 2, b.readInt() * 0.1));
+ register(74, fmbXXX, (p, b) -> p.set(Position.PREFIX_TEMP + 3, b.readInt() * 0.1));
+ register(75, fmbXXX, (p, b) -> p.set(Position.PREFIX_TEMP + 4, b.readInt() * 0.1));
+ register(78, null, (p, b) -> {
+ long driverUniqueId = b.readLong();
+ if (driverUniqueId > 0) {
+ p.set(Position.KEY_DRIVER_UNIQUE_ID, String.format("%016X", driverUniqueId));
+ }
+ });
+ register(80, fmbXXX, (p, b) -> p.set("dataMode", b.readUnsignedByte()));
+ register(81, fmbXXX, (p, b) -> p.set(Position.KEY_OBD_SPEED, b.readUnsignedByte()));
+ register(82, fmbXXX, (p, b) -> p.set(Position.KEY_THROTTLE, b.readUnsignedByte()));
+ register(83, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_USED, b.readUnsignedInt() * 0.1));
+ register(84, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_LEVEL, b.readUnsignedShort() * 0.1));
+ register(85, fmbXXX, (p, b) -> p.set(Position.KEY_RPM, b.readUnsignedShort()));
+ register(87, fmbXXX, (p, b) -> p.set(Position.KEY_OBD_ODOMETER, b.readUnsignedInt()));
+ register(89, fmbXXX, (p, b) -> p.set("fuelLevelPercentage", b.readUnsignedByte()));
+ register(90, null, (p, b) -> p.set(Position.KEY_DOOR, b.readUnsignedShort()));
+ register(110, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_CONSUMPTION, b.readUnsignedShort() * 0.1));
+ register(113, fmbXXX, (p, b) -> p.set(Position.KEY_BATTERY_LEVEL, b.readUnsignedByte()));
+ register(179, null, (p, b) -> p.set(Position.PREFIX_OUT + 1, b.readUnsignedByte() > 0));
+ register(180, null, (p, b) -> p.set(Position.PREFIX_OUT + 2, b.readUnsignedByte() > 0));
+ register(181, null, (p, b) -> p.set(Position.KEY_PDOP, b.readUnsignedShort() * 0.1));
+ register(182, null, (p, b) -> p.set(Position.KEY_HDOP, b.readUnsignedShort() * 0.1));
+ register(199, null, (p, b) -> p.set(Position.KEY_ODOMETER_TRIP, b.readUnsignedInt()));
+ register(200, fmbXXX, (p, b) -> p.set("sleepMode", b.readUnsignedByte()));
+ register(205, fmbXXX, (p, b) -> p.set("cid2g", b.readUnsignedShort()));
+ register(206, fmbXXX, (p, b) -> p.set("lac", b.readUnsignedShort()));
+ register(232, fmbXXX, (p, b) -> p.set("cngStatus", b.readUnsignedByte() > 0));
+ register(233, fmbXXX, (p, b) -> p.set("cngUsed", b.readUnsignedInt() * 0.1));
+ register(234, fmbXXX, (p, b) -> p.set("cngLevel", b.readUnsignedShort()));
+ register(235, fmbXXX, (p, b) -> p.set("oilLevel", b.readUnsignedByte()));
+ register(236, null, (p, b) -> {
+ p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_GENERAL : null);
+ });
+ register(239, null, (p, b) -> p.set(Position.KEY_IGNITION, b.readUnsignedByte() > 0));
+ register(240, null, (p, b) -> p.set(Position.KEY_MOTION, b.readUnsignedByte() > 0));
+ register(241, null, (p, b) -> p.set(Position.KEY_OPERATOR, b.readUnsignedInt()));
+ register(246, fmbXXX, (p, b) -> {
+ p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_TOW : null);
+ });
+ register(247, fmbXXX, (p, b) -> {
+ p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_ACCIDENT : null);
+ });
+ register(249, fmbXXX, (p, b) -> {
+ p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_JAMMING : null);
+ });
+ register(252, fmbXXX, (p, b) -> {
+ p.set(Position.KEY_ALARM, b.readUnsignedByte() > 0 ? Position.ALARM_POWER_CUT : null);
+ });
+ register(253, null, (p, b) -> {
+ switch (b.readUnsignedByte()) {
+ case 1:
+ p.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
+ break;
+ case 2:
+ p.set(Position.KEY_ALARM, Position.ALARM_BRAKING);
+ break;
+ case 3:
+ p.set(Position.KEY_ALARM, Position.ALARM_CORNERING);
+ break;
+ default:
+ break;
+ }
+ });
+ register(636, fmbXXX, (p, b) -> p.set("cid4g", b.readUnsignedInt()));
}
private void decodeGh3000Parameter(Position position, int id, ByteBuf buf, int length) {
switch (id) {
case 1:
- position.set(Position.KEY_BATTERY_LEVEL, readValue(buf, length, false));
+ position.set(Position.KEY_BATTERY_LEVEL, readValue(buf, length));
break;
case 2:
- position.set("usbConnected", readValue(buf, length, false) == 1);
+ position.set("usbConnected", readValue(buf, length) == 1);
break;
case 5:
- position.set("uptime", readValue(buf, length, false));
+ position.set("uptime", readValue(buf, length));
break;
case 20:
- position.set(Position.KEY_HDOP, readValue(buf, length, false) * 0.1);
+ position.set(Position.KEY_HDOP, readValue(buf, length) * 0.1);
break;
case 21:
- position.set(Position.KEY_VDOP, readValue(buf, length, false) * 0.1);
+ position.set(Position.KEY_VDOP, readValue(buf, length) * 0.1);
break;
case 22:
- position.set(Position.KEY_PDOP, readValue(buf, length, false) * 0.1);
+ position.set(Position.KEY_PDOP, readValue(buf, length) * 0.1);
break;
case 67:
- position.set(Position.KEY_BATTERY, readValue(buf, length, false) * 0.001);
+ position.set(Position.KEY_BATTERY, readValue(buf, length) * 0.001);
break;
case 221:
- position.set("button", readValue(buf, length, false));
+ position.set("button", readValue(buf, length));
break;
case 222:
- if (readValue(buf, length, false) == 1) {
+ if (readValue(buf, length) == 1) {
position.set(Position.KEY_ALARM, Position.ALARM_SOS);
}
break;
case 240:
- position.set(Position.KEY_MOTION, readValue(buf, length, false) == 1);
+ position.set(Position.KEY_MOTION, readValue(buf, length) == 1);
break;
case 244:
- position.set(Position.KEY_ROAMING, readValue(buf, length, false) == 1);
+ position.set(Position.KEY_ROAMING, readValue(buf, length) == 1);
break;
default:
- position.set(Position.PREFIX_IO + id, readValue(buf, length, false));
+ position.set(Position.PREFIX_IO + id, readValue(buf, length));
break;
}
}
- private void decodeParameter(Position position, int id, ByteBuf buf, int length, int codec) {
+ private void decodeParameter(Position position, int id, ByteBuf buf, int length, int codec, String model) {
if (codec == CODEC_GH3000) {
decodeGh3000Parameter(position, id, buf, length);
} else {
- decodeOtherParameter(position, id, buf, length);
+ int index = buf.readerIndex();
+ boolean decoded = false;
+ for (var entry : PARAMETERS.getOrDefault(id, new HashMap<>()).entrySet()) {
+ if (entry.getKey() == null || model != null && entry.getKey().contains(model)) {
+ entry.getValue().accept(position, buf);
+ decoded = true;
+ break;
+ }
+ }
+ if (decoded) {
+ buf.readerIndex(index + length);
+ } else {
+ position.set(Position.PREFIX_IO + id, readValue(buf, length));
+ }
}
}
- private void decodeNetwork(Position position) {
- long cid = position.getLong(Position.PREFIX_IO + 205);
- int lac = position.getInteger(Position.PREFIX_IO + 206);
- if (cid != 0 && lac != 0) {
- CellTower cellTower = CellTower.fromLacCid(lac, cid);
- long operator = position.getInteger(Position.KEY_OPERATOR);
- if (operator >= 1000) {
- cellTower.setOperator(operator);
+ private void decodeCell(
+ Position position, Network network, String mncKey, String lacKey, String cidKey, String rssiKey) {
+ if (position.hasAttribute(mncKey) && position.hasAttribute(lacKey) && position.hasAttribute(cidKey)) {
+ CellTower cellTower = CellTower.from(
+ getConfig().getInteger(Keys.GEOLOCATION_MCC),
+ ((Number) position.getAttributes().remove(mncKey)).intValue(),
+ ((Number) position.getAttributes().remove(lacKey)).intValue(),
+ ((Number) position.getAttributes().remove(cidKey)).longValue());
+ cellTower.setSignalStrength(((Number) position.getAttributes().remove(rssiKey)).intValue());
+ network.addCellTower(cellTower);
+ }
+ }
+
+ private void decodeNetwork(Position position, String model) {
+ if ("TAT100".equals(model)) {
+ Network network = new Network();
+ decodeCell(position, network, "io1200", "io287", "io288", "io289");
+ decodeCell(position, network, "io1201", "io290", "io291", "io292");
+ decodeCell(position, network, "io1202", "io293", "io294", "io295");
+ decodeCell(position, network, "io1203", "io296", "io297", "io298");
+ if (network.getCellTowers() != null) {
+ position.setNetwork(network);
+ }
+ } else {
+ Integer cid2g = (Integer) position.getAttributes().remove("cid2g");
+ Long cid4g = (Long) position.getAttributes().remove("cid4g");
+ Integer lac = (Integer) position.getAttributes().remove("lac");
+ if (lac != null && (cid2g != null || cid4g != null)) {
+ Network network = new Network();
+ CellTower cellTower;
+ if (cid2g != null) {
+ cellTower = CellTower.fromLacCid(getConfig(), lac, cid2g);
+ } else {
+ cellTower = CellTower.fromLacCid(getConfig(), lac, cid4g);
+ network.setRadioType("lte");
+ }
+ long operator = position.getInteger(Position.KEY_OPERATOR);
+ if (operator >= 1000) {
+ cellTower.setOperator(operator);
+ }
+ network.addCellTower(cellTower);
+ position.setNetwork(new Network(cellTower));
}
- position.setNetwork(new Network(cellTower));
}
}
@@ -384,7 +419,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
}
}
- private void decodeLocation(Position position, ByteBuf buf, int codec) {
+ private void decodeLocation(Position position, ByteBuf buf, int codec, String model) {
int globalMask = 0x0f;
@@ -422,7 +457,8 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
}
if (BitUtil.check(locationMask, 5)) {
- CellTower cellTower = CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedShort());
+ CellTower cellTower = CellTower.fromLacCid(
+ getConfig(), buf.readUnsignedShort(), buf.readUnsignedShort());
if (BitUtil.check(locationMask, 6)) {
cellTower.setSignalStrength((int) buf.readUnsignedByte());
@@ -480,7 +516,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
if (BitUtil.check(globalMask, 1)) {
int cnt = readExtByte(buf, codec, CODEC_8_EXT);
for (int j = 0; j < cnt; j++) {
- decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 1, codec);
+ decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 1, codec, model);
}
}
@@ -488,7 +524,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
if (BitUtil.check(globalMask, 2)) {
int cnt = readExtByte(buf, codec, CODEC_8_EXT);
for (int j = 0; j < cnt; j++) {
- decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 2, codec);
+ decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 2, codec, model);
}
}
@@ -496,7 +532,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
if (BitUtil.check(globalMask, 3)) {
int cnt = readExtByte(buf, codec, CODEC_8_EXT);
for (int j = 0; j < cnt; j++) {
- decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 4, codec);
+ decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 4, codec, model);
}
}
@@ -504,7 +540,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
if (codec == CODEC_8 || codec == CODEC_8_EXT || codec == CODEC_16) {
int cnt = readExtByte(buf, codec, CODEC_8_EXT);
for (int j = 0; j < cnt; j++) {
- decodeOtherParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 8);
+ decodeParameter(position, readExtByte(buf, codec, CODEC_8_EXT, CODEC_16), buf, 8, codec, model);
}
}
@@ -558,7 +594,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
}
}
- decodeNetwork(position);
+ decodeNetwork(position, model);
}
@@ -574,10 +610,10 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
int count = buf.readUnsignedByte();
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
-
if (deviceSession == null) {
return null;
}
+ String model = getCacheManager().getObject(Device.class, deviceSession.getDeviceId()).getModel();
for (int i = 0; i < count; i++) {
Position position = new Position(getProtocolName());
@@ -589,17 +625,21 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedByte(); // type
int length = buf.readInt() - 4;
getLastLocation(position, new Date(buf.readUnsignedInt() * 1000));
- if (isPrintable(buf, length)) {
- position.set(Position.KEY_RESULT,
- buf.readCharSequence(length, StandardCharsets.US_ASCII).toString().trim());
+ if (BufferUtil.isPrintable(buf, length)) {
+ String data = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString().trim();
+ if (data.startsWith("GTSL")) {
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, data.split("\\|")[4]);
+ } else {
+ position.set(Position.KEY_RESULT, data);
+ }
} else {
position.set(Position.KEY_RESULT,
ByteBufUtil.hexDump(buf.readSlice(length)));
}
} else if (codec == CODEC_12) {
- decodeSerial(channel, remoteAddress, position, buf);
+ decodeSerial(channel, remoteAddress, deviceSession, position, buf);
} else {
- decodeLocation(position, buf, codec);
+ decodeLocation(position, buf, codec, model);
}
if (!position.getOutdated() || !position.getAttributes().isEmpty()) {
@@ -636,9 +676,11 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
}
}
- private Object decodeTcp(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception {
+ private Object decodeTcp(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
- if (buf.getUnsignedShort(0) > 0) {
+ if (buf.readableBytes() == 1 && buf.readUnsignedByte() == 0xff) {
+ return null;
+ } else if (buf.getUnsignedShort(0) > 0) {
parseIdentification(channel, remoteAddress, buf);
} else {
buf.skipBytes(4);
@@ -648,7 +690,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- private Object decodeUdp(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws Exception {
+ private Object decodeUdp(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
buf.readUnsignedShort(); // length
buf.readUnsignedShort(); // packet id
diff --git a/src/main/java/org/traccar/protocol/TeraTrackProtocol.java b/src/main/java/org/traccar/protocol/TeraTrackProtocol.java
index 0303b4b5a..e872ddf42 100644
--- a/src/main/java/org/traccar/protocol/TeraTrackProtocol.java
+++ b/src/main/java/org/traccar/protocol/TeraTrackProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TeraTrackProtocol extends BaseProtocol {
- public TeraTrackProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TeraTrackProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new JsonFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java
index c36da2aed..be4b98e4c 100644
--- a/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java
@@ -17,14 +17,14 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.Position;
-import javax.json.Json;
-import javax.json.JsonObject;
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
import java.io.StringReader;
import java.net.SocketAddress;
import java.text.DateFormat;
@@ -63,7 +63,7 @@ public class TeraTrackProtocolDecoder extends BaseProtocolDecoder {
position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(json.getString("Speed"))));
position.set(Position.KEY_ODOMETER, Integer.parseInt(json.getString("Mileage")));
- position.set(Position.KEY_BLOCKED, json.getString("LockOpen").equals("0"));
+ position.set(Position.KEY_LOCK, json.getString("LockOpen").equals("0"));
position.set(Position.KEY_DRIVER_UNIQUE_ID, json.getString("CardNo"));
position.set(Position.KEY_ALARM, json.getString("LowPower").equals("1") ? Position.ALARM_LOW_POWER : null);
position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(json.getString("Power")));
diff --git a/src/main/java/org/traccar/protocol/ThinkPowerProtocol.java b/src/main/java/org/traccar/protocol/ThinkPowerProtocol.java
index ece1b0544..b23dadf08 100644
--- a/src/main/java/org/traccar/protocol/ThinkPowerProtocol.java
+++ b/src/main/java/org/traccar/protocol/ThinkPowerProtocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class ThinkPowerProtocol extends BaseProtocol {
- public ThinkPowerProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public ThinkPowerProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 2, 2, 0));
pipeline.addLast(new ThinkPowerProtocolDecoder(ThinkPowerProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/ThinkPowerProtocolDecoder.java b/src/main/java/org/traccar/protocol/ThinkPowerProtocolDecoder.java
index b3f943078..e7ab23e5b 100644
--- a/src/main/java/org/traccar/protocol/ThinkPowerProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ThinkPowerProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2021 - 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.
@@ -19,7 +19,8 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.helper.BufferUtil;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Checksum;
@@ -64,8 +65,8 @@ public class ThinkPowerProtocolDecoder extends BaseProtocolDecoder {
switch (type) {
case 0x01:
position.setValid(true);
- position.setLatitude(buf.readInt() * 0.0000001);
- position.setLongitude(buf.readInt() * 0.0000001);
+ position.setLatitude(BufferUtil.readSignedMagnitudeInt(buf) * 0.0000001);
+ position.setLongitude(BufferUtil.readSignedMagnitudeInt(buf) * 0.0000001);
position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort() * 0.1));
position.setCourse(buf.readUnsignedShort() * 0.01);
break;
diff --git a/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java b/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java
index ca1237cef..34b80ba87 100644
--- a/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java
+++ b/src/main/java/org/traccar/protocol/ThinkRaceProtocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class ThinkRaceProtocol extends BaseProtocol {
- public ThinkRaceProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public ThinkRaceProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2 + 12 + 1 + 1, 2, 2, 0));
pipeline.addLast(new ThinkRaceProtocolDecoder(ThinkRaceProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/ThinkRaceProtocolDecoder.java b/src/main/java/org/traccar/protocol/ThinkRaceProtocolDecoder.java
index 0928b25e0..796b726ea 100644
--- a/src/main/java/org/traccar/protocol/ThinkRaceProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/ThinkRaceProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -104,7 +104,7 @@ public class ThinkRaceProtocolDecoder extends BaseProtocolDecoder {
position.setCourse(buf.readUnsignedByte());
position.setNetwork(new Network(
- CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedShort())));
+ CellTower.fromLacCid(getConfig(), buf.readUnsignedShort(), buf.readUnsignedShort())));
return position;
diff --git a/src/main/java/org/traccar/protocol/ThurayaProtocol.java b/src/main/java/org/traccar/protocol/ThurayaProtocol.java
new file mode 100644
index 000000000..33d486f6b
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/ThurayaProtocol.java
@@ -0,0 +1,39 @@
+/*
+ * 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.protocol;
+
+import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
+
+public class ThurayaProtocol extends BaseProtocol {
+
+ @Inject
+ public ThurayaProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 2, 2, -4, 0));
+ pipeline.addLast(new ThurayaProtocolDecoder(ThurayaProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/ThurayaProtocolDecoder.java b/src/main/java/org/traccar/protocol/ThurayaProtocolDecoder.java
new file mode 100644
index 000000000..a287ece34
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/ThurayaProtocolDecoder.java
@@ -0,0 +1,195 @@
+/*
+ * 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.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.NetworkMessage;
+import org.traccar.Protocol;
+import org.traccar.helper.BitUtil;
+import org.traccar.helper.DateBuilder;
+import org.traccar.model.Position;
+import org.traccar.session.DeviceSession;
+
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.LinkedList;
+import java.util.List;
+
+public class ThurayaProtocolDecoder extends BaseProtocolDecoder {
+
+ public ThurayaProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ public static final int MSG_EVENT = 0x5101;
+ public static final int MSG_PERIODIC_REPORT = 0x7101;
+ public static final int MSG_SETTING_RESPONSE = 0x8115;
+ public static final int MSG_ACK = 0x9901;
+
+ private static int checksum(ByteBuffer buf) {
+ int crc = 0;
+ while (buf.hasRemaining()) {
+ crc += buf.get();
+ }
+ crc = ~crc;
+ crc += 1;
+ return crc;
+ }
+
+ private void sendResponse(Channel channel, SocketAddress remoteAddress, long id, int type) {
+ if (channel != null) {
+ ByteBuf response = Unpooled.buffer();
+ response.writeCharSequence("#T", StandardCharsets.US_ASCII);
+ response.writeShort(15); // length
+ response.writeShort(MSG_ACK);
+ response.writeInt((int) id);
+ response.writeShort(type);
+ response.writeShort(1); // server ok
+ response.writeShort(checksum(response.nioBuffer()));
+ channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
+ }
+ }
+
+ private void decodeLocation(ByteBuf buf, Position position) {
+
+ position.setValid(true);
+
+ DateBuilder dateBuilder = new DateBuilder();
+
+ int date = buf.readInt();
+ dateBuilder.setDay(date % 100);
+ date /= 100;
+ dateBuilder.setMonth(date % 100);
+ date /= 100;
+ dateBuilder.setYear(date);
+
+ int time = buf.readInt();
+ dateBuilder.setSecond(time % 100);
+ time /= 100;
+ dateBuilder.setMinute(time % 100);
+ time /= 100;
+ dateBuilder.setHour(time);
+
+ position.setTime(dateBuilder.getDate());
+
+ position.setLongitude(buf.readInt() / 1000000.0);
+ position.setLatitude(buf.readInt() / 1000000.0);
+
+ int data = buf.readUnsignedShort();
+
+ int ignition = BitUtil.from(data, 12);
+ if (ignition == 1) {
+ position.set(Position.KEY_IGNITION, true);
+ } else if (ignition == 2) {
+ position.set(Position.KEY_IGNITION, false);
+ }
+
+ position.setCourse(BitUtil.to(data, 12));
+ position.setSpeed(buf.readShort());
+
+ position.set(Position.KEY_RPM, buf.readShort());
+
+ position.set("data", readString(buf));
+ }
+
+ private String decodeAlarm(int event) {
+ switch (event) {
+ case 10:
+ return Position.ALARM_VIBRATION;
+ case 11:
+ return Position.ALARM_OVERSPEED;
+ case 12:
+ return Position.ALARM_POWER_CUT;
+ case 13:
+ return Position.ALARM_LOW_BATTERY;
+ case 18:
+ return Position.ALARM_GPS_ANTENNA_CUT;
+ case 20:
+ return Position.ALARM_ACCELERATION;
+ case 21:
+ return Position.ALARM_BRAKING;
+ default:
+ return null;
+ }
+ }
+
+ private String readString(ByteBuf buf) {
+ int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0);
+ CharSequence value = buf.readCharSequence(endIndex - buf.readerIndex(), StandardCharsets.US_ASCII);
+ buf.readUnsignedByte(); // delimiter
+ return value.toString();
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ByteBuf buf = (ByteBuf) msg;
+
+ buf.skipBytes(2); // service
+ buf.readUnsignedShort(); // length
+ int type = buf.readUnsignedShort();
+ long id = buf.readUnsignedInt();
+
+ sendResponse(channel, remoteAddress, id, type);
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id));
+ if (deviceSession == null) {
+ return null;
+ }
+
+ if (type == MSG_EVENT) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ decodeLocation(buf, position);
+
+ int event = buf.readUnsignedByte();
+ position.set(Position.KEY_ALARM, decodeAlarm(event));
+ position.set(Position.KEY_EVENT, event);
+ position.set("eventData", readString(buf));
+
+ return position;
+
+ } else if (type == MSG_PERIODIC_REPORT) {
+
+ List<Position> positions = new LinkedList<>();
+
+ int count = buf.readUnsignedByte();
+ for (int i = 0; i < count; i++) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ decodeLocation(buf, position);
+
+ positions.add(position);
+
+ }
+
+ return positions;
+
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/Tk102Protocol.java b/src/main/java/org/traccar/protocol/Tk102Protocol.java
index 9f2463cd6..b6a82981b 100644
--- a/src/main/java/org/traccar/protocol/Tk102Protocol.java
+++ b/src/main/java/org/traccar/protocol/Tk102Protocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Tk102Protocol extends BaseProtocol {
- public Tk102Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Tk102Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 1 + 1 + 10, 1, 1, 0));
pipeline.addLast(new Tk102ProtocolDecoder(Tk102Protocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/Tk102ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tk102ProtocolDecoder.java
index da0c6928b..af29fbc21 100644
--- a/src/main/java/org/traccar/protocol/Tk102ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Tk102ProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/Tk103Protocol.java b/src/main/java/org/traccar/protocol/Tk103Protocol.java
index ff0bedfb7..b641ef083 100644
--- a/src/main/java/org/traccar/protocol/Tk103Protocol.java
+++ b/src/main/java/org/traccar/protocol/Tk103Protocol.java
@@ -21,11 +21,15 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class Tk103Protocol extends BaseProtocol {
- public Tk103Protocol() {
+ @Inject
+ public Tk103Protocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_GET_DEVICE_STATUS,
@@ -45,9 +49,9 @@ public class Tk103Protocol extends BaseProtocol {
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME,
Command.TYPE_OUTPUT_CONTROL);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new Tk103FrameDecoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
@@ -55,9 +59,9 @@ public class Tk103Protocol extends BaseProtocol {
pipeline.addLast(new Tk103ProtocolDecoder(Tk103Protocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new Tk103ProtocolEncoder(Tk103Protocol.this));
diff --git a/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java
index ff33cb103..6c926da90 100644
--- a/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,10 +15,12 @@
*/
package org.traccar.protocol;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.helper.DataConverter;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.config.Keys;
@@ -36,11 +38,15 @@ import java.util.regex.Pattern;
public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
- private final boolean decodeLow;
+ private boolean decodeLow;
public Tk103ProtocolDecoder(Protocol protocol) {
super(protocol);
- decodeLow = Context.getConfig().getBoolean(Keys.PROTOCOL_DECODE_LOW.withPrefix(getProtocolName()));
+ }
+
+ @Override
+ protected void init() {
+ decodeLow = getConfig().getBoolean(Keys.PROTOCOL_DECODE_LOW.withPrefix(getProtocolName()));
}
private static final Pattern PATTERN = new PatternBuilder()
@@ -96,6 +102,16 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
.any()
.compile();
+ private static final Pattern PATTERN_CELL = new PatternBuilder()
+ .text("(")
+ .number("(d{12})") // device id
+ .expression(".{4}") // type
+ .number("(?:d{15})?,") // imei
+ .expression("(.+),") // cell
+ .number("(d{8})") // odometer
+ .text(")")
+ .compile();
+
private static final Pattern PATTERN_NETWORK = new PatternBuilder()
.text("(").optional()
.number("(d{12})") // device id
@@ -294,6 +310,39 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private Position decodeCell(Channel channel, SocketAddress remoteAddress, String sentence) {
+ Parser parser = new Parser(PATTERN_CELL, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ getLastLocation(position, null);
+
+ Network network = new Network();
+
+ String[] cells = parser.next().split("\n");
+ for (String cell : cells) {
+ String[] values = cell.substring(1, cell.length() - 1).split(",");
+ network.addCellTower(CellTower.from(
+ Integer.parseInt(values[0]), Integer.parseInt(values[1]),
+ Integer.parseInt(values[2]), Integer.parseInt(values[3])));
+ }
+
+ position.setNetwork(network);
+
+ position.set(Position.KEY_ODOMETER, parser.nextLong(16, 0));
+
+ return position;
+ }
+
private Position decodeNetwork(Channel channel, SocketAddress remoteAddress, String sentence) {
Parser parser = new Parser(PATTERN_NETWORK, sentence);
if (!parser.matches()) {
@@ -402,6 +451,106 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private Position decodeBms(Channel channel, SocketAddress remoteAddress, String sentence) {
+ String id = sentence.substring(1, 13);
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ getLastLocation(position, null);
+
+ String payload = sentence.substring(1 + 12 + 4, sentence.length() - 1);
+
+ if (sentence.startsWith("BS50", 1 + 12)) {
+
+ ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(payload));
+
+ buf.readUnsignedByte();
+ buf.readUnsignedByte();
+ buf.readUnsignedByte(); // header
+
+ int batteryCount = buf.readUnsignedByte();
+ for (int i = 1; i <= 24; i++) {
+ int voltage = buf.readUnsignedShortLE();
+ if (i <= batteryCount) {
+ position.set("battery" + i, voltage * 0.001);
+ }
+ }
+
+ position.set(Position.KEY_CHARGE, buf.readUnsignedByte() == 0);
+ position.set("current", buf.readUnsignedShortLE() * 0.1);
+ position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01);
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ position.set("batteryOverheat", buf.readUnsignedByte() > 0);
+ position.set("chargeProtection", buf.readUnsignedByte() > 0);
+ position.set("dischargeProtection", buf.readUnsignedByte() > 0);
+ buf.readUnsignedByte(); // drop line
+ buf.readUnsignedByte(); // balanced
+ position.set("cycles", buf.readUnsignedShortLE());
+ position.set("faultAlarm", buf.readUnsignedByte());
+
+ buf.skipBytes(6);
+
+ int temperatureCount = buf.readUnsignedByte();
+ position.set("powerTemp", buf.readUnsignedByte() - 40);
+ position.set("equilibriumTemp", buf.readUnsignedByte() - 40);
+ for (int i = 1; i <= 7; i++) {
+ int temperature = buf.readUnsignedByte() - 40;
+ if (i <= temperatureCount) {
+ position.set("batteryTemp" + i, temperature);
+ }
+ }
+
+ position.set("calibrationCapacity", buf.readUnsignedShortLE() * 0.01);
+ position.set("dischargeCapacity", buf.readUnsignedIntLE());
+
+ } else {
+
+ String[] values = payload.split(",");
+ for (String value : values) {
+ String[] pair = value.split(":");
+ int key = Integer.parseInt(pair[0], 16);
+ ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex(pair[1]));
+ switch (key) {
+ case 0x90:
+ position.set("cumulativeVoltage", buf.readUnsignedShortLE() * 0.1);
+ position.set("gatherVoltage", buf.readUnsignedShortLE() * 0.1);
+ position.set("current", (buf.readUnsignedShortLE() - 30000) * 0.1);
+ position.set("soc", buf.readUnsignedShortLE() * 0.1);
+ break;
+ case 0x91:
+ position.set("maxCellVoltage", buf.readUnsignedShortLE() * 0.001);
+ position.set("maxCellVoltageCount", buf.readUnsignedByte());
+ position.set("minCellVoltage", buf.readUnsignedShortLE() * 0.001);
+ position.set("minCellVoltageCount", buf.readUnsignedByte());
+ break;
+ case 0x92:
+ position.set("maxTemp", buf.readUnsignedByte() - 40);
+ position.set("maxTempCount", buf.readUnsignedByte());
+ position.set("minTemp", buf.readUnsignedByte() - 40);
+ position.set("minTempCount", buf.readUnsignedByte());
+ break;
+ case 0x96:
+ buf.readUnsignedByte(); // frame
+ while (buf.isReadable()) {
+ position.set("cellTemp" + buf.readerIndex(), buf.readUnsignedByte() - 40);
+ }
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ }
+
+ return position;
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -419,7 +568,9 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
}
}
- if (sentence.contains("ZC20")) {
+ if (sentence.indexOf('{') > 0 && sentence.indexOf('}') > 0) {
+ return decodeCell(channel, remoteAddress, sentence);
+ } else if (sentence.contains("ZC20")) {
return decodeBattery(channel, remoteAddress, sentence);
} else if (sentence.contains("BZ00")) {
return decodeNetwork(channel, remoteAddress, sentence);
@@ -429,6 +580,8 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder {
return decodeLbsWifi(channel, remoteAddress, sentence);
} else if (sentence.contains("BV00")) {
return decodeVin(channel, remoteAddress, sentence);
+ } else if (sentence.contains("BS50") || sentence.contains("BS51")) {
+ return decodeBms(channel, remoteAddress, sentence);
}
Parser parser = new Parser(PATTERN, sentence);
diff --git a/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java
index 5d7e63920..e3e1ae961 100644
--- a/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/Tk103ProtocolEncoder.java
@@ -16,10 +16,11 @@
*/
package org.traccar.protocol;
-import org.traccar.Context;
+import org.traccar.Protocol;
import org.traccar.StringProtocolEncoder;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.AttributeUtil;
import org.traccar.model.Command;
-import org.traccar.Protocol;
public class Tk103ProtocolEncoder extends StringProtocolEncoder {
@@ -42,12 +43,12 @@ public class Tk103ProtocolEncoder extends StringProtocolEncoder {
@Override
protected Object encodeCommand(Command command) {
- boolean alternative = forceAlternative || Context.getIdentityManager().lookupAttributeBoolean(
- command.getDeviceId(), getProtocolName() + ".alternative", false, false, true);
+ boolean alternative = AttributeUtil.lookup(
+ getCacheManager(), Keys.PROTOCOL_ALTERNATIVE.withPrefix(getProtocolName()), command.getDeviceId());
initDevicePassword(command, "123456");
- if (alternative) {
+ if (alternative || forceAlternative) {
switch (command.getType()) {
case Command.TYPE_CUSTOM:
return formatAlt(command, "%s", Command.KEY_DATA);
diff --git a/src/main/java/org/traccar/protocol/Tlt2hProtocol.java b/src/main/java/org/traccar/protocol/Tlt2hProtocol.java
index 12fd92afa..6763e9b6b 100644
--- a/src/main/java/org/traccar/protocol/Tlt2hProtocol.java
+++ b/src/main/java/org/traccar/protocol/Tlt2hProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Tlt2hProtocol extends BaseProtocol {
- public Tlt2hProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Tlt2hProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(32 * 1024, "##\r\n"));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java
index ad7dfa886..e85bdf9b3 100644
--- a/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Tlt2hProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 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,7 +17,8 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.model.CellTower;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
@@ -55,6 +56,12 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder {
private static final Pattern PATTERN_POSITION = new PatternBuilder()
.text("#")
.number("(?:(dd)|x*)") // cell or voltage
+ .groupBegin()
+ .number("#(d+),") // mcc
+ .number("(d+),") // mnc
+ .number("(x+),") // lac
+ .number("(x+)") // cell id
+ .groupEnd("?")
.text("$GPRMC,")
.number("(dd)(dd)(dd).d+,") // time (hhmmss.sss)
.expression("([AVL]),") // validity
@@ -71,6 +78,12 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder {
private static final Pattern PATTERN_WIFI = new PatternBuilder()
.text("#")
.number("(?:(dd)|x+)") // cell or voltage
+ .groupBegin()
+ .number("#(d+),") // mcc
+ .number("(d+),") // mnc
+ .number("(x+),") // lac
+ .number("(x+)") // cell id
+ .groupEnd("?")
.text("$WIFI,")
.number("(dd)(dd)(dd).d+,") // time (hhmmss.sss)
.expression("[AVL],") // validity
@@ -168,6 +181,13 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_BATTERY, parser.nextInt() * 0.1);
}
+ if (parser.hasNext(4)) {
+ Network network = new Network();
+ network.addCellTower(CellTower.from(
+ parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt()));
+ position.setNetwork(network);
+ }
+
DateBuilder dateBuilder = new DateBuilder()
.setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
@@ -191,11 +211,16 @@ public class Tlt2hProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_BATTERY, parser.nextInt() * 0.1);
+ Network network = new Network();
+ if (parser.hasNext(4)) {
+ network.addCellTower(CellTower.from(
+ parser.nextInt(), parser.nextInt(), parser.nextHexInt(), parser.nextHexInt()));
+ }
+
DateBuilder dateBuilder = new DateBuilder()
.setTime(parser.nextInt(), parser.nextInt(), parser.nextInt());
String[] values = parser.next().split(",");
- Network network = new Network();
for (int i = 0; i < values.length / 2; i++) {
String mac = values[i * 2 + 1].replaceAll("(..)", "$1:").substring(0, 17);
network.addWifiAccessPoint(WifiAccessPoint.from(mac, Integer.parseInt(values[i * 2])));
diff --git a/src/main/java/org/traccar/protocol/TlvProtocol.java b/src/main/java/org/traccar/protocol/TlvProtocol.java
index 94f5da94f..f99676d23 100644
--- a/src/main/java/org/traccar/protocol/TlvProtocol.java
+++ b/src/main/java/org/traccar/protocol/TlvProtocol.java
@@ -19,13 +19,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TlvProtocol extends BaseProtocol {
- public TlvProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TlvProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '\0'));
pipeline.addLast(new TlvProtocolDecoder(TlvProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/TlvProtocolDecoder.java b/src/main/java/org/traccar/protocol/TlvProtocolDecoder.java
index 36cf7859f..7870c778a 100644
--- a/src/main/java/org/traccar/protocol/TlvProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TlvProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.UnitsConverter;
diff --git a/src/main/java/org/traccar/protocol/TmgProtocol.java b/src/main/java/org/traccar/protocol/TmgProtocol.java
index 020332ce7..dbba648be 100644
--- a/src/main/java/org/traccar/protocol/TmgProtocol.java
+++ b/src/main/java/org/traccar/protocol/TmgProtocol.java
@@ -20,13 +20,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TmgProtocol extends BaseProtocol {
- public TmgProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TmgProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new TmgFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/TmgProtocolDecoder.java b/src/main/java/org/traccar/protocol/TmgProtocolDecoder.java
index d27849f8c..00dc2a09b 100644
--- a/src/main/java/org/traccar/protocol/TmgProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TmgProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/TopflytechProtocol.java b/src/main/java/org/traccar/protocol/TopflytechProtocol.java
index 303072bdb..a658235ab 100644
--- a/src/main/java/org/traccar/protocol/TopflytechProtocol.java
+++ b/src/main/java/org/traccar/protocol/TopflytechProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TopflytechProtocol extends BaseProtocol {
- public TopflytechProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TopflytechProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ')'));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/TopflytechProtocolDecoder.java b/src/main/java/org/traccar/protocol/TopflytechProtocolDecoder.java
index 6de053c32..92a7b5c9d 100644
--- a/src/main/java/org/traccar/protocol/TopflytechProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TopflytechProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/TopinProtocol.java b/src/main/java/org/traccar/protocol/TopinProtocol.java
index d28afbf94..1a558f617 100644
--- a/src/main/java/org/traccar/protocol/TopinProtocol.java
+++ b/src/main/java/org/traccar/protocol/TopinProtocol.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2019 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,16 +18,23 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class TopinProtocol extends BaseProtocol {
- public TopinProtocol() {
- setSupportedDataCommands(
- Command.TYPE_SOS_NUMBER);
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TopinProtocol(Config config) {
+ if (!config.getBoolean(Keys.PROTOCOL_DISABLE_COMMANDS.withPrefix(getName()))) {
+ setSupportedDataCommands(
+ Command.TYPE_SOS_NUMBER);
+ }
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new TopinProtocolEncoder(TopinProtocol.this));
pipeline.addLast(new TopinProtocolDecoder(TopinProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java
index 4fe261aa4..b5dd3c4b9 100644
--- a/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TopinProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BcdUtil;
@@ -48,7 +48,11 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_GPS = 0x10;
public static final int MSG_GPS_OFFLINE = 0x11;
public static final int MSG_STATUS = 0x13;
+ public static final int MSG_SLEEP = 0x14;
+ public static final int MSG_FACTORY_RESET = 0x15;
public static final int MSG_WIFI_OFFLINE = 0x17;
+ public static final int MSG_LBS_WIFI = 0x18;
+ public static final int MSG_LBS_WIFI_OFFLINE = 0x19;
public static final int MSG_TIME_UPDATE = 0x30;
public static final int MSG_SOS_NUMBER = 0x41;
public static final int MSG_WIFI = 0x69;
@@ -216,7 +220,8 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder {
return position;
- } else if (type == MSG_WIFI || type == MSG_WIFI_OFFLINE) {
+ } else if (type == MSG_WIFI || type == MSG_WIFI_OFFLINE
+ || type == MSG_LBS_WIFI || type == MSG_LBS_WIFI_OFFLINE) {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
diff --git a/src/main/java/org/traccar/protocol/TotemProtocol.java b/src/main/java/org/traccar/protocol/TotemProtocol.java
index 417a4d6b0..b02d4f1fc 100644
--- a/src/main/java/org/traccar/protocol/TotemProtocol.java
+++ b/src/main/java/org/traccar/protocol/TotemProtocol.java
@@ -20,11 +20,15 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class TotemProtocol extends BaseProtocol {
- public TotemProtocol() {
+ @Inject
+ public TotemProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_REBOOT_DEVICE,
@@ -46,9 +50,9 @@ public class TotemProtocol extends BaseProtocol {
Command.TYPE_ENGINE_STOP
);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new TotemFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java b/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java
index 58c66031e..6f039c324 100644
--- a/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -135,13 +135,17 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
private static final Pattern PATTERN4 = new PatternBuilder()
.text("$$") // header
.number("dddd") // length
- .number("(xx)") // type
+ .number("xx") // type
.number("(d+)|") // imei
.number("(x{8})") // status
.number("(dd)(dd)(dd)") // date (yymmdd)
.number("(dd)(dd)(dd)") // time (hhmmss)
+ .groupBegin()
.number("(dd)") // battery
.number("(dd)") // external power
+ .or()
+ .number("(ddd)") // battery
+ .groupEnd()
.number("(dddd)") // adc 1
.groupBegin()
.groupBegin()
@@ -166,12 +170,27 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
.number("(d{7})") // odometer
.number("(dd)(dd.dddd)([NS])") // latitude
.number("(ddd)(dd.dddd)([EW])") // longitude
+ .number("dddd").optional() // temperature
.number("dddd") // serial number
.number("xx") // checksum
.any()
.compile();
- private static final Pattern PATTERN_OBD = new PatternBuilder()
+ private static final Pattern PATTERN_E2 = new PatternBuilder()
+ .text("$$") // header
+ .number("dddd") // length
+ .number("xx") // type
+ .number("(d+)|") // imei
+ .number("(dd)(dd)(dd)") // date (yymmdd)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .number("(-?d+.d+),") // longitude
+ .number("(-?d+.d+),") // latitude
+ .expression("(.+)") // rfid
+ .number("|xx") // checksum
+ .any()
+ .compile();
+
+ private static final Pattern PATTERN_E5 = new PatternBuilder()
.text("$$") // header
.number("dddd") // length
.number("xx") // type
@@ -252,7 +271,20 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
}
}
- private boolean decode12(Position position, Parser parser, Pattern pattern) {
+ private Position decode12(Channel channel, SocketAddress remoteAddress, String sentence, Pattern pattern) {
+
+ Parser parser = new Parser(pattern, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
if (parser.hasNext()) {
position.set(Position.KEY_ALARM, decodeAlarm123(Short.parseShort(parser.next(), 16)));
@@ -278,7 +310,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
year = parser.nextInt(0);
}
if (year == 0) {
- return false; // ignore invalid data
+ return null; // ignore invalid data
}
dateBuilder.setDate(year, month, day);
position.setTime(dateBuilder.getDate());
@@ -320,16 +352,29 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
int lac = parser.nextHexInt(0);
int cid = parser.nextHexInt(0);
if (lac != 0 && cid != 0) {
- position.setNetwork(new Network(CellTower.fromLacCid(lac, cid)));
+ position.setNetwork(new Network(CellTower.fromLacCid(getConfig(), lac, cid)));
}
position.set(Position.PREFIX_TEMP + 1, parser.next());
position.set(Position.KEY_ODOMETER, parser.nextDouble(0) * 1000);
- return true;
+ return position;
}
- private boolean decode3(Position position, Parser parser) {
+ private Position decode3(Channel channel, SocketAddress remoteAddress, String sentence) {
+
+ Parser parser = new Parser(PATTERN3, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
if (parser.hasNext()) {
position.set(Position.KEY_ALARM, decodeAlarm123(Short.parseShort(parser.next(), 16)));
@@ -346,7 +391,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.PREFIX_TEMP + 2, parser.next());
position.setNetwork(new Network(
- CellTower.fromLacCid(parser.nextHexInt(0), parser.nextHexInt(0))));
+ CellTower.fromLacCid(getConfig(), parser.nextHexInt(0), parser.nextHexInt(0))));
position.setValid(parser.next().equals("A"));
position.set(Position.KEY_SATELLITES, parser.nextInt());
@@ -358,10 +403,36 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
position.setLatitude(parser.nextCoordinate());
position.setLongitude(parser.nextCoordinate());
- return true;
+ return position;
}
- private boolean decode4(Position position, Parser parser) {
+ private Position decode4(Channel channel, SocketAddress remoteAddress, String sentence) {
+
+ int type = Integer.parseInt(sentence.substring(6, 8), 16);
+
+ switch (type) {
+ case 0xE2:
+ return decodeE2(channel, remoteAddress, sentence);
+ case 0xE5:
+ return decodeE5(channel, remoteAddress, sentence);
+ default:
+ break;
+ }
+
+ Parser parser = new Parser(PATTERN4, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.set(Position.KEY_ALARM, decodeAlarm4(type));
long status = parser.nextHexLong();
@@ -379,8 +450,13 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
position.setTime(parser.nextDateTime());
- position.set(Position.KEY_BATTERY, parser.nextDouble() * 0.1);
- position.set(Position.KEY_POWER, parser.nextDouble());
+ if (parser.hasNext(2)) {
+ position.set(Position.KEY_BATTERY, parser.nextDouble() * 0.1);
+ position.set(Position.KEY_POWER, parser.nextDouble());
+ }
+ if (parser.hasNext()) {
+ position.set(Position.KEY_BATTERY, parser.nextDouble() * 0.01);
+ }
position.set(Position.PREFIX_ADC + 1, parser.next());
position.set(Position.PREFIX_ADC + 2, parser.next());
@@ -403,7 +479,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
int mcc = parser.nextInt();
cellTower = CellTower.from(mcc, mnc, lac, cid);
} else {
- cellTower = CellTower.fromLacCid(lac, cid);
+ cellTower = CellTower.fromLacCid(getConfig(), lac, cid);
}
position.set(Position.KEY_SATELLITES, parser.nextInt());
cellTower.setSignalStrength(parser.nextInt());
@@ -417,10 +493,48 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
position.setLatitude(parser.nextCoordinate());
position.setLongitude(parser.nextCoordinate());
- return true;
+ return position;
}
- private boolean decodeObd(Position position, Parser parser) {
+ private Position decodeE2(Channel channel, SocketAddress remoteAddress, String sentence) {
+
+ Parser parser = new Parser(PATTERN_E2, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setValid(true);
+ position.setTime(parser.nextDateTime());
+ position.setLongitude(parser.nextDouble());
+ position.setLatitude(parser.nextDouble());
+
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next());
+
+ return position;
+ }
+
+ private Position decodeE5(Channel channel, SocketAddress remoteAddress, String sentence) {
+
+ Parser parser = new Parser(PATTERN_E5, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
position.setValid(true);
position.setTime(parser.nextDateTime());
@@ -441,7 +555,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_THROTTLE, parser.nextInt());
position.set(Position.KEY_FUEL_LEVEL, parser.nextInt());
- return true;
+ return position;
}
@Override
@@ -449,50 +563,23 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
String sentence = (String) msg;
- Pattern pattern = PATTERN3;
- if (sentence.contains("$Cloud")) {
- pattern = PATTERN_OBD;
- } else if (sentence.charAt(2) == '0') {
- pattern = PATTERN4;
+
+ Position position;
+ if (sentence.charAt(2) == '0') {
+ position = decode4(channel, remoteAddress, sentence);
} else if (sentence.contains("$GPRMC")) {
- pattern = PATTERN1;
+ position = decode12(channel, remoteAddress, sentence, PATTERN1);
} else {
int index = sentence.indexOf('|');
if (index != -1 && sentence.indexOf('|', index + 1) != -1) {
- pattern = PATTERN2;
+ position = decode12(channel, remoteAddress, sentence, PATTERN2);
+ } else {
+ position = decode3(channel, remoteAddress, sentence);
}
}
- Parser parser = new Parser(pattern, sentence);
- if (!parser.matches()) {
- return null;
- }
-
- Position position = new Position(getProtocolName());
-
- if (pattern == PATTERN4) {
- position.set(Position.KEY_ALARM, decodeAlarm4(parser.nextHexInt()));
- }
-
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
- if (deviceSession == null) {
- return null;
- }
- position.setDeviceId(deviceSession.getDeviceId());
-
- boolean result;
- if (pattern == PATTERN1 || pattern == PATTERN2) {
- result = decode12(position, parser, pattern);
- } else if (pattern == PATTERN3) {
- result = decode3(position, parser);
- } else if (pattern == PATTERN4) {
- result = decode4(position, parser);
- } else {
- result = decodeObd(position, parser);
- }
-
if (channel != null) {
- if (pattern == PATTERN4) {
+ if (sentence.charAt(2) == '0') {
String response = "$$0014AA" + sentence.substring(sentence.length() - 6, sentence.length() - 2);
response += String.format("%02X", Checksum.xor(response)).toUpperCase();
channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
@@ -501,7 +588,7 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
}
}
- return result ? position : null;
+ return position;
}
}
diff --git a/src/main/java/org/traccar/protocol/Tr20Protocol.java b/src/main/java/org/traccar/protocol/Tr20Protocol.java
index 1b71db03f..3b3fc02b6 100644
--- a/src/main/java/org/traccar/protocol/Tr20Protocol.java
+++ b/src/main/java/org/traccar/protocol/Tr20Protocol.java
@@ -21,22 +21,26 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Tr20Protocol extends BaseProtocol {
- public Tr20Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Tr20Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new Tr20ProtocolDecoder(Tr20Protocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new Tr20ProtocolDecoder(Tr20Protocol.this));
diff --git a/src/main/java/org/traccar/protocol/Tr20ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tr20ProtocolDecoder.java
index 2f11bd152..0e1c7568b 100644
--- a/src/main/java/org/traccar/protocol/Tr20ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Tr20ProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
@@ -52,7 +52,7 @@ public class Tr20ProtocolDecoder extends BaseProtocolDecoder {
.number("(ddd)(dd.d+),") // longitude
.number("(d+),") // speed
.number("(d+),") // course
- .number("(?:NA|[FC]?(-?d+)[^,]*),") // temperature
+ .number("(?:NA|[BFC]?(-?d+)[^,]*),") // temperature
.number("(x{8}),") // status
.number("(d+)") // event
.any()
diff --git a/src/main/java/org/traccar/protocol/Tr900Protocol.java b/src/main/java/org/traccar/protocol/Tr900Protocol.java
index b70521b35..c5f357604 100644
--- a/src/main/java/org/traccar/protocol/Tr900Protocol.java
+++ b/src/main/java/org/traccar/protocol/Tr900Protocol.java
@@ -21,22 +21,26 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Tr900Protocol extends BaseProtocol {
- public Tr900Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Tr900Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new Tr900ProtocolDecoder(Tr900Protocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new Tr900ProtocolDecoder(Tr900Protocol.this));
diff --git a/src/main/java/org/traccar/protocol/Tr900ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tr900ProtocolDecoder.java
index 319194c21..da0e8d292 100644
--- a/src/main/java/org/traccar/protocol/Tr900ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Tr900ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/TrackboxProtocol.java b/src/main/java/org/traccar/protocol/TrackboxProtocol.java
index 5da5abd64..eadcd07f9 100644
--- a/src/main/java/org/traccar/protocol/TrackboxProtocol.java
+++ b/src/main/java/org/traccar/protocol/TrackboxProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TrackboxProtocol extends BaseProtocol {
- public TrackboxProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TrackboxProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/TrackboxProtocolDecoder.java b/src/main/java/org/traccar/protocol/TrackboxProtocolDecoder.java
index db8022738..10483d445 100644
--- a/src/main/java/org/traccar/protocol/TrackboxProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TrackboxProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/TrakMateProtocol.java b/src/main/java/org/traccar/protocol/TrakMateProtocol.java
index bda5df10f..f4e7c5e60 100644
--- a/src/main/java/org/traccar/protocol/TrakMateProtocol.java
+++ b/src/main/java/org/traccar/protocol/TrakMateProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TrakMateProtocol extends BaseProtocol {
- public TrakMateProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TrakMateProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/TrakMateProtocolDecoder.java b/src/main/java/org/traccar/protocol/TrakMateProtocolDecoder.java
index 4d5cb18f5..b1f50dc10 100644
--- a/src/main/java/org/traccar/protocol/TrakMateProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TrakMateProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java b/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java
index e4c94dc77..72cadf21a 100644
--- a/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java
+++ b/src/main/java/org/traccar/protocol/TramigoFrameDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,9 +29,13 @@ public class TramigoFrameDecoder extends BaseFrameDecoder {
return null;
}
+ int protocol = buf.getUnsignedByte(buf.readerIndex());
+
int length;
- if (buf.getUnsignedByte(buf.readerIndex()) == 0x80) {
+ if (protocol == 0x80) {
length = buf.getUnsignedShortLE(buf.readerIndex() + 6);
+ } else if (protocol == 0x02 || protocol == 0x04) {
+ length = buf.getUnsignedShortLE(buf.readerIndex() + 1);
} else {
length = buf.getUnsignedShort(buf.readerIndex() + 6);
}
diff --git a/src/main/java/org/traccar/protocol/TramigoProtocol.java b/src/main/java/org/traccar/protocol/TramigoProtocol.java
index f683ccc5d..5d8baf2a9 100644
--- a/src/main/java/org/traccar/protocol/TramigoProtocol.java
+++ b/src/main/java/org/traccar/protocol/TramigoProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TramigoProtocol extends BaseProtocol {
- public TramigoProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TramigoProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new TramigoFrameDecoder());
pipeline.addLast(new TramigoProtocolDecoder(TramigoProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java
index e42e2f670..4a9a9a58f 100644
--- a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2014 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,9 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.helper.BitUtil;
+import org.traccar.helper.Checksum;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateUtil;
@@ -29,6 +31,7 @@ import org.traccar.model.Position;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
+import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
@@ -42,9 +45,6 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
- public static final int MSG_COMPACT = 0x0100;
- public static final int MSG_FULL = 0x00FE;
-
private static final String[] DIRECTIONS = new String[] {"N", "NE", "E", "SE", "S", "SW", "W", "NW"};
@Override
@@ -54,34 +54,47 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder {
ByteBuf buf = (ByteBuf) msg;
int protocol = buf.readUnsignedByte();
- boolean legacy = protocol == 0x80;
+
+ if (protocol == 0x01) {
+ return decode01(channel, remoteAddress, buf);
+ } else if (protocol == 0x04) {
+ return decode04(channel, remoteAddress, buf);
+ } else if (protocol == 0x80) {
+ return decode80(channel, remoteAddress, buf);
+ }
+
+ return null;
+ }
+
+ private Position decode01(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
buf.readUnsignedByte(); // version id
- int index = legacy ? buf.readUnsignedShort() : buf.readUnsignedShortLE();
- int type = legacy ? buf.readUnsignedShort() : buf.readUnsignedShortLE();
- buf.readUnsignedShort(); // length
- buf.readUnsignedShort(); // mask
- buf.readUnsignedShort(); // checksum
- long id = legacy ? buf.readUnsignedInt() : buf.readUnsignedIntLE();
- buf.readUnsignedInt(); // time
+ int index = buf.readUnsignedShortLE();
+ int type = buf.readUnsignedShortLE();
- Position position = new Position(getProtocolName());
- position.set(Position.KEY_INDEX, index);
- position.setValid(true);
+ if (type == 0x0100 || type == 0x00FE) {
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id));
- if (deviceSession == null) {
- return null;
- }
- position.setDeviceId(deviceSession.getDeviceId());
+ buf.readUnsignedShort(); // length
+ buf.readUnsignedShort(); // mask
+ buf.readUnsignedShort(); // checksum
+ long id = buf.readUnsignedIntLE();
+ buf.readUnsignedInt(); // time
- if (protocol == 0x01 && (type == MSG_COMPACT || type == MSG_FULL)) {
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id));
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+ position.set(Position.KEY_INDEX, index);
// need to send ack?
buf.readUnsignedShortLE(); // report trigger
buf.readUnsignedShortLE(); // state flag
+ position.setValid(true);
position.setLatitude(buf.readUnsignedIntLE() * 0.0000001);
position.setLongitude(buf.readUnsignedIntLE() * 0.0000001);
@@ -105,56 +118,183 @@ public class TramigoProtocolDecoder extends BaseProtocolDecoder {
return position;
- } else if (legacy) {
+ }
- if (channel != null) {
- channel.writeAndFlush(new NetworkMessage(
- Unpooled.copiedBuffer("gprs,ack," + index, StandardCharsets.US_ASCII), remoteAddress));
- }
+ return null;
- String sentence = buf.toString(StandardCharsets.US_ASCII);
+ }
- Pattern pattern = Pattern.compile("(-?\\d+\\.\\d+), (-?\\d+\\.\\d+)");
- Matcher matcher = pattern.matcher(sentence);
- if (!matcher.find()) {
- return null;
- }
- position.setLatitude(Double.parseDouble(matcher.group(1)));
- position.setLongitude(Double.parseDouble(matcher.group(2)));
-
- pattern = Pattern.compile("([NSWE]{1,2}) with speed (\\d+) km/h");
- matcher = pattern.matcher(sentence);
- if (matcher.find()) {
- for (int i = 0; i < DIRECTIONS.length; i++) {
- if (matcher.group(1).equals(DIRECTIONS[i])) {
- position.setCourse(i * 45.0);
- break;
- }
- }
- position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(matcher.group(2))));
- }
+ private Position decode04(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
- pattern = Pattern.compile("(\\d{1,2}:\\d{2}(:\\d{2})? \\w{3} \\d{1,2})");
- matcher = pattern.matcher(sentence);
- if (!matcher.find()) {
- return null;
- }
- DateFormat dateFormat = new SimpleDateFormat(
- matcher.group(2) != null ? "HH:mm:ss MMM d yyyy" : "HH:mm MMM d yyyy", Locale.ENGLISH);
- position.setTime(DateUtil.correctYear(
- dateFormat.parse(matcher.group(1) + " " + Calendar.getInstance().get(Calendar.YEAR))));
-
- if (sentence.contains("Ignition on detected")) {
- position.set(Position.KEY_IGNITION, true);
- } else if (sentence.contains("Ignition off detected")) {
- position.set(Position.KEY_IGNITION, false);
+ buf.readUnsignedShortLE(); // length
+ buf.readUnsignedShortLE(); // checksum
+ int index = buf.readUnsignedShortLE();
+ long id1 = buf.readUnsignedIntLE();
+ long id2 = buf.readUnsignedIntLE();
+ long time = buf.readUnsignedIntLE();
+
+ String id = String.format("%08d%07d", id1, id2);
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ if (channel != null) {
+ ByteBuf response = Unpooled.buffer();
+ response.writeByte(0x04); // protocol
+ response.writeShortLE(24); // length
+ response.writeShortLE(0); // checksum
+ response.writeShortLE(index);
+ response.writeIntLE((int) id1);
+ response.writeIntLE((int) id2);
+ response.writeIntLE((int) time);
+
+ response.writeByte(0xff); // acknowledgement
+ response.writeShortLE(index);
+ response.writeShortLE(0); // success
+
+ response.setShortLE(3, Checksum.crc16(Checksum.CRC16_CCITT_FALSE, response.nioBuffer()));
+
+ channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress()));
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+ position.set(Position.KEY_INDEX, index);
+
+ position.setDeviceTime(new Date(time * 1000));
+
+ while (buf.isReadable()) {
+ int type = buf.readUnsignedByte();
+ switch (type) {
+ case 0:
+ position.set(Position.KEY_EVENT, buf.readUnsignedShortLE());
+ buf.readUnsignedIntLE(); // event data
+
+ int status = buf.readUnsignedShortLE();
+ position.set(Position.KEY_IGNITION, BitUtil.check(status, 5));
+ position.set(Position.KEY_STATUS, status);
+
+ position.setValid(true);
+ position.setLatitude(buf.readIntLE() * 0.00001);
+ position.setLongitude(buf.readIntLE() * 0.00001);
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShortLE()));
+ position.setCourse(buf.readUnsignedShortLE());
+
+ position.set(Position.KEY_RSSI, buf.readUnsignedByte());
+ position.set(Position.KEY_GPS, buf.readUnsignedByte());
+ position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
+ position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedShortLE());
+ position.set("maxAcceleration", buf.readUnsignedShortLE() * 0.001);
+ position.set("maxDeceleration", buf.readUnsignedShortLE() * 0.001);
+ buf.readUnsignedShortLE(); // bearing to landmark
+ buf.readUnsignedIntLE(); // distance to landmark
+
+ position.setFixTime(new Date(buf.readUnsignedIntLE() * 1000));
+
+ buf.readUnsignedByte(); // reserved
+ break;
+ case 1:
+ buf.skipBytes(buf.readUnsignedShortLE() - 3); // landmark
+ break;
+ case 4:
+ buf.skipBytes(53); // trip
+ break;
+ case 20:
+ buf.skipBytes(32); // extended
+ break;
+ case 22:
+ buf.readUnsignedByte(); // zone flag
+ buf.skipBytes(buf.readUnsignedShortLE()); // zone name
+ break;
+ case 30:
+ buf.skipBytes(79); // system status
+ break;
+ case 40:
+ buf.skipBytes(40); // analog
+ break;
+ case 50:
+ buf.skipBytes(buf.readUnsignedShortLE() - 3); // console
+ break;
+ case 255:
+ buf.skipBytes(4); // acknowledgement
+ break;
+ default:
+ throw new IllegalArgumentException(String.format("Unknown type %d", type));
}
+ }
- return position;
+ return position.getValid() ? position : null;
+
+ }
+ private Position decode80(Channel channel, SocketAddress remoteAddress, ByteBuf buf) throws ParseException {
+
+ buf.readUnsignedByte(); // version id
+ int index = buf.readUnsignedShort();
+ buf.readUnsignedShort(); // type
+
+ buf.readUnsignedShort(); // length
+ buf.readUnsignedShort(); // mask
+ buf.readUnsignedShort(); // checksum
+ long id = buf.readUnsignedInt();
+ buf.readUnsignedInt(); // time
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, String.valueOf(id));
+ if (deviceSession == null) {
+ return null;
}
- return null;
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+ position.set(Position.KEY_INDEX, index);
+
+ if (channel != null) {
+ channel.writeAndFlush(new NetworkMessage(
+ Unpooled.copiedBuffer("gprs,ack," + index, StandardCharsets.US_ASCII), remoteAddress));
+ }
+
+ String sentence = buf.toString(StandardCharsets.US_ASCII);
+
+ Pattern pattern = Pattern.compile("(-?\\d+\\.\\d+), (-?\\d+\\.\\d+)");
+ Matcher matcher = pattern.matcher(sentence);
+ if (!matcher.find()) {
+ return null;
+ }
+ position.setLatitude(Double.parseDouble(matcher.group(1)));
+ position.setLongitude(Double.parseDouble(matcher.group(2)));
+ position.setValid(true);
+
+ pattern = Pattern.compile("([NSWE]{1,2}) with speed (\\d+) km/h");
+ matcher = pattern.matcher(sentence);
+ if (matcher.find()) {
+ for (int i = 0; i < DIRECTIONS.length; i++) {
+ if (matcher.group(1).equals(DIRECTIONS[i])) {
+ position.setCourse(i * 45.0);
+ break;
+ }
+ }
+ position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(matcher.group(2))));
+ }
+
+ pattern = Pattern.compile("(\\d{1,2}:\\d{2}(:\\d{2})? \\w{3} \\d{1,2})");
+ matcher = pattern.matcher(sentence);
+ if (!matcher.find()) {
+ return null;
+ }
+ DateFormat dateFormat = new SimpleDateFormat(
+ matcher.group(2) != null ? "HH:mm:ss MMM d yyyy" : "HH:mm MMM d yyyy", Locale.ENGLISH);
+ position.setTime(DateUtil.correctYear(
+ dateFormat.parse(matcher.group(1) + " " + Calendar.getInstance().get(Calendar.YEAR))));
+
+ if (sentence.contains("Ignition on detected")) {
+ position.set(Position.KEY_IGNITION, true);
+ } else if (sentence.contains("Ignition off detected")) {
+ position.set(Position.KEY_IGNITION, false);
+ }
+
+ return position;
+
}
}
diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocol.java b/src/main/java/org/traccar/protocol/TranSyncProtocol.java
new file mode 100644
index 000000000..fb37a1ab4
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/TranSyncProtocol.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
+
+public class TranSyncProtocol extends BaseProtocol {
+
+ @Inject
+ public TranSyncProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 1, 2, 0));
+ pipeline.addLast(new TranSyncProtocolDecoder(TranSyncProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java
new file mode 100644
index 000000000..816b5d2cf
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/TranSyncProtocolDecoder.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.Protocol;
+import org.traccar.helper.BitUtil;
+import org.traccar.helper.DateBuilder;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.CellTower;
+import org.traccar.model.Network;
+import org.traccar.model.Position;
+import org.traccar.session.DeviceSession;
+
+import java.net.SocketAddress;
+
+public class TranSyncProtocolDecoder extends BaseProtocolDecoder {
+
+ public TranSyncProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private String decodeAlarm(int value) {
+ switch (value) {
+ case 4:
+ return Position.ALARM_LOW_BATTERY;
+ case 6:
+ return Position.ALARM_POWER_RESTORED;
+ case 10:
+ return Position.ALARM_SOS;
+ case 13:
+ return Position.ALARM_BRAKING;
+ case 14:
+ return Position.ALARM_ACCELERATION;
+ case 17:
+ return Position.ALARM_OVERSPEED;
+ case 23:
+ return Position.ALARM_ACCIDENT;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ protected Object decode(Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ByteBuf buf = (ByteBuf) msg;
+
+ buf.readUnsignedShort(); // header
+ buf.readByte(); // length
+
+ int lac = buf.readUnsignedShort();
+
+ String deviceId = ByteBufUtil.hexDump(buf.readSlice(8));
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, deviceId);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ buf.readUnsignedShort(); // index
+ buf.readUnsignedByte(); // type
+
+ position.setTime(new DateBuilder()
+ .setDate(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .getDate());
+
+ double latitude = buf.readUnsignedInt() / 1800000.0;
+ double longitude = buf.readUnsignedInt() / 1800000.0;
+
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte()));
+ position.setCourse(buf.readUnsignedShort());
+
+ int mnc = buf.readUnsignedByte();
+ int cid = buf.readUnsignedShort();
+ int status0 = buf.readUnsignedByte();
+
+ position.setValid(BitUtil.check(status0, 0));
+ position.setLatitude(BitUtil.check(status0, 1) ? latitude : -latitude);
+ position.setLongitude(BitUtil.check(status0, 2) ? longitude : -longitude);
+
+ position.set(Position.PREFIX_OUT + 1, BitUtil.check(status0, 7));
+ position.set(Position.PREFIX_OUT + 2, BitUtil.check(status0, 6));
+ position.set(Position.PREFIX_IN + 3, BitUtil.check(status0, 5));
+ if (BitUtil.check(status0, 4)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_POWER_OFF);
+ }
+ position.set(Position.KEY_IGNITION, BitUtil.check(status0, 3));
+
+ buf.readUnsignedByte(); // reserved
+
+ int event = buf.readUnsignedByte();
+ position.set(Position.KEY_ALARM, decodeAlarm(event));
+ position.set(Position.KEY_EVENT, event);
+
+ int status3 = buf.readUnsignedByte();
+ if (BitUtil.check(status3, 7)) {
+ position.set(Position.KEY_ARCHIVE, true);
+ }
+ if (BitUtil.check(status3, 5)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_GPS_ANTENNA_CUT);
+ }
+
+ int rssi = buf.readUnsignedByte();
+ CellTower cellTower = CellTower.fromLacCid(getConfig(), lac, cid);
+ cellTower.setMobileNetworkCode(mnc);
+ cellTower.setSignalStrength(rssi);
+ position.setNetwork(new Network(cellTower));
+
+ position.set(Position.KEY_BATTERY, (double) (buf.readUnsignedByte() / 10));
+ position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
+ position.set(Position.KEY_HDOP, buf.readUnsignedByte());
+ position.set(Position.PREFIX_ADC + 1, (short) buf.readUnsignedShort());
+
+ if (buf.readableBytes() > 5) {
+ buf.readUnsignedByte(); // odometer id
+ int length = buf.readUnsignedByte();
+ if (length > 0) {
+ position.set(Position.KEY_ODOMETER, buf.readBytes(length).readInt());
+ }
+ }
+ if (buf.readableBytes() > 5) {
+ buf.readUnsignedByte(); // rfid id
+ int length = buf.readUnsignedByte();
+ if (length > 0) {
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, ByteBufUtil.hexDump(buf.readSlice(length)));
+ }
+ }
+ if (buf.readableBytes() > 5) {
+ buf.readUnsignedByte(); // adc2 id
+ int length = buf.readUnsignedByte();
+ if (length > 0) {
+ position.set(Position.PREFIX_ADC + 2, buf.readUnsignedShort());
+ }
+ }
+ if (buf.readableBytes() > 5) {
+ buf.readUnsignedByte(); // adc3 id
+ int length = buf.readUnsignedByte();
+ if (length > 0 && length <= buf.readableBytes() - 2) {
+ position.set(Position.PREFIX_ADC + 3, buf.readUnsignedShort());
+ }
+ }
+
+ return position;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/TrvProtocol.java b/src/main/java/org/traccar/protocol/TrvProtocol.java
index 99a164cf1..7bdf3d2d0 100644
--- a/src/main/java/org/traccar/protocol/TrvProtocol.java
+++ b/src/main/java/org/traccar/protocol/TrvProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TrvProtocol extends BaseProtocol {
- public TrvProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TrvProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java b/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java
index e62cdf404..9df29ae1b 100644
--- a/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/Tt8850Protocol.java b/src/main/java/org/traccar/protocol/Tt8850Protocol.java
index 66a13da9e..8e2800d90 100644
--- a/src/main/java/org/traccar/protocol/Tt8850Protocol.java
+++ b/src/main/java/org/traccar/protocol/Tt8850Protocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Tt8850Protocol extends BaseProtocol {
- public Tt8850Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Tt8850Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "$"));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/Tt8850ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tt8850ProtocolDecoder.java
index 1010528c4..cbc983000 100644
--- a/src/main/java/org/traccar/protocol/Tt8850ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Tt8850ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/TytanProtocol.java b/src/main/java/org/traccar/protocol/TytanProtocol.java
index 32e9acae1..4fd3c807f 100644
--- a/src/main/java/org/traccar/protocol/TytanProtocol.java
+++ b/src/main/java/org/traccar/protocol/TytanProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class TytanProtocol extends BaseProtocol {
- public TytanProtocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public TytanProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new TytanProtocolDecoder(TytanProtocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/TytanProtocolDecoder.java b/src/main/java/org/traccar/protocol/TytanProtocolDecoder.java
index 93d3a63d2..6169e0545 100644
--- a/src/main/java/org/traccar/protocol/TytanProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TytanProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/TzoneProtocol.java b/src/main/java/org/traccar/protocol/TzoneProtocol.java
index 6e855d138..2df721049 100644
--- a/src/main/java/org/traccar/protocol/TzoneProtocol.java
+++ b/src/main/java/org/traccar/protocol/TzoneProtocol.java
@@ -15,18 +15,21 @@
*/
package org.traccar.protocol;
+import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
-import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
+import jakarta.inject.Inject;
public class TzoneProtocol extends BaseProtocol {
- public TzoneProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public TzoneProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(256, 2, 2, 2, 0));
pipeline.addLast(new TzoneProtocolDecoder(TzoneProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java b/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java
index 819c42471..f0b1e709d 100644
--- a/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java
@@ -20,8 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.config.Keys;
@@ -205,30 +204,39 @@ public class TzoneProtocolDecoder extends BaseProtocolDecoder {
}
- private void decodeTags(Position position, ByteBuf buf) {
+ private void decodeTags(Position position, ByteBuf buf, int hardware) {
int blockLength = buf.readUnsignedShort();
int blockEnd = buf.readerIndex() + blockLength;
if (blockLength > 0) {
- buf.readUnsignedByte(); // tag type
+ int type = buf.readUnsignedByte();
- int count = buf.readUnsignedByte();
- int tagLength = buf.readUnsignedByte();
+ if (hardware != 0x153 || type >= 2) {
- for (int i = 1; i <= count; i++) {
- int tagEnd = buf.readerIndex() + tagLength;
+ int count = buf.readUnsignedByte();
+ int tagLength = buf.readUnsignedByte();
+
+ for (int i = 1; i <= count; i++) {
+ int tagEnd = buf.readerIndex() + tagLength;
+
+ buf.readUnsignedByte(); // status
+ buf.readUnsignedShortLE(); // battery voltage
- buf.readUnsignedByte(); // status
- buf.readUnsignedShortLE(); // battery voltage
+ position.set(Position.PREFIX_TEMP + i, (buf.readShortLE() & 0x3fff) * 0.1);
+
+ buf.readUnsignedByte(); // humidity
+ buf.readUnsignedByte(); // rssi
+
+ buf.readerIndex(tagEnd);
+ }
- position.set(Position.PREFIX_TEMP + i, (buf.readShortLE() & 0x3fff) * 0.1);
+ } else if (type == 1) {
- buf.readUnsignedByte(); // humidity
- buf.readUnsignedByte(); // rssi
+ position.set(Position.KEY_CARD, buf.readCharSequence(
+ blockEnd - buf.readerIndex(), StandardCharsets.UTF_8).toString());
- buf.readerIndex(tagEnd);
}
}
@@ -284,7 +292,7 @@ public class TzoneProtocolDecoder extends BaseProtocolDecoder {
if (hardware == 0x10A || hardware == 0x10B || hardware == 0x406) {
position.setNetwork(new Network(
- CellTower.fromLacCid(buf.readUnsignedShort(), buf.readUnsignedShort())));
+ CellTower.fromLacCid(getConfig(), buf.readUnsignedShort(), buf.readUnsignedShort())));
} else if (hardware == 0x407) {
@@ -365,13 +373,13 @@ public class TzoneProtocolDecoder extends BaseProtocolDecoder {
}
- if (hardware == 0x406) {
+ if (hardware == 0x153 || hardware == 0x406) {
- decodeTags(position, buf);
+ decodeTags(position, buf, hardware);
}
- if (Context.getConfig().getBoolean(Keys.PROTOCOL_ACK.withPrefix(getProtocolName()))) {
+ if (getConfig().getBoolean(Keys.PROTOCOL_ACK.withPrefix(getProtocolName()))) {
sendResponse(channel, remoteAddress, buf.getUnsignedShort(buf.writerIndex() - 6));
}
diff --git a/src/main/java/org/traccar/protocol/UlbotechProtocol.java b/src/main/java/org/traccar/protocol/UlbotechProtocol.java
index dfe5235f0..f8c4f1960 100644
--- a/src/main/java/org/traccar/protocol/UlbotechProtocol.java
+++ b/src/main/java/org/traccar/protocol/UlbotechProtocol.java
@@ -18,16 +18,20 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class UlbotechProtocol extends BaseProtocol {
- public UlbotechProtocol() {
+ @Inject
+ public UlbotechProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new UlbotechFrameDecoder());
pipeline.addLast(new UlbotechProtocolEncoder(UlbotechProtocol.this));
pipeline.addLast(new UlbotechProtocolDecoder(UlbotechProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/UlbotechProtocolDecoder.java b/src/main/java/org/traccar/protocol/UlbotechProtocolDecoder.java
index 7fec0bf8b..c9b35158e 100644
--- a/src/main/java/org/traccar/protocol/UlbotechProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/UlbotechProtocolDecoder.java
@@ -20,7 +20,7 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -37,6 +37,7 @@ import org.traccar.model.Position;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Date;
+import java.util.TimeZone;
import java.util.regex.Pattern;
public class UlbotechProtocolDecoder extends BaseProtocolDecoder {
@@ -214,16 +215,17 @@ public class UlbotechProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- if (deviceSession.getTimeZone() == null) {
- deviceSession.setTimeZone(getTimeZone(deviceSession.getDeviceId()));
+ if (!deviceSession.contains(DeviceSession.KEY_TIMEZONE)) {
+ deviceSession.set(DeviceSession.KEY_TIMEZONE, getTimeZone(deviceSession.getDeviceId()));
}
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
+ TimeZone timeZone = deviceSession.get(DeviceSession.KEY_TIMEZONE);
long seconds = buf.readUnsignedInt() & 0x7fffffffL;
seconds += 946684800L; // 2000-01-01 00:00
- seconds -= deviceSession.getTimeZone().getRawOffset() / 1000;
+ seconds -= timeZone.getRawOffset() / 1000;
Date time = new Date(seconds * 1000);
boolean hasLocation = false;
diff --git a/src/main/java/org/traccar/protocol/UproProtocol.java b/src/main/java/org/traccar/protocol/UproProtocol.java
index 4e60ffeb6..cbec9777d 100644
--- a/src/main/java/org/traccar/protocol/UproProtocol.java
+++ b/src/main/java/org/traccar/protocol/UproProtocol.java
@@ -20,13 +20,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class UproProtocol extends BaseProtocol {
- public UproProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public UproProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#'));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new UproProtocolDecoder(UproProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java
index 9f236a7e5..ed714e464 100644
--- a/src/main/java/org/traccar/protocol/UproProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/UproProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
@@ -67,12 +67,11 @@ public class UproProtocolDecoder extends BaseProtocolDecoder {
DateBuilder dateBuilder = new DateBuilder()
.setTime(parser.nextInt(0), parser.nextInt(0), parser.nextInt(0));
- position.setValid(true);
position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN));
position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN));
int flags = parser.nextInt(0);
- position.setValid(BitUtil.check(flags, 0));
+ position.setValid(!BitUtil.check(flags, 0));
if (!BitUtil.check(flags, 1)) {
position.setLatitude(-position.getLatitude());
}
diff --git a/src/main/java/org/traccar/protocol/UuxProtocol.java b/src/main/java/org/traccar/protocol/UuxProtocol.java
index 41b59d829..63727cb94 100644
--- a/src/main/java/org/traccar/protocol/UuxProtocol.java
+++ b/src/main/java/org/traccar/protocol/UuxProtocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class UuxProtocol extends BaseProtocol {
- public UuxProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public UuxProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 1));
pipeline.addLast(new UuxProtocolDecoder(UuxProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/UuxProtocolDecoder.java b/src/main/java/org/traccar/protocol/UuxProtocolDecoder.java
index 1081fa811..b9065e7f3 100644
--- a/src/main/java/org/traccar/protocol/UuxProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/UuxProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
diff --git a/src/main/java/org/traccar/protocol/V680Protocol.java b/src/main/java/org/traccar/protocol/V680Protocol.java
index dc0922cd4..587a0c8f7 100644
--- a/src/main/java/org/traccar/protocol/V680Protocol.java
+++ b/src/main/java/org/traccar/protocol/V680Protocol.java
@@ -21,22 +21,26 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class V680Protocol extends BaseProtocol {
- public V680Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public V680Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "##"));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new V680ProtocolDecoder(V680Protocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new V680ProtocolDecoder(V680Protocol.this));
diff --git a/src/main/java/org/traccar/protocol/V680ProtocolDecoder.java b/src/main/java/org/traccar/protocol/V680ProtocolDecoder.java
index 40267022b..237aea39b 100644
--- a/src/main/java/org/traccar/protocol/V680ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/V680ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/VisiontekProtocol.java b/src/main/java/org/traccar/protocol/VisiontekProtocol.java
index 2c6af45a8..83bcd37ff 100644
--- a/src/main/java/org/traccar/protocol/VisiontekProtocol.java
+++ b/src/main/java/org/traccar/protocol/VisiontekProtocol.java
@@ -21,13 +21,17 @@ import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class VisiontekProtocol extends BaseProtocol {
- public VisiontekProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public VisiontekProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, '#'));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/VisiontekProtocolDecoder.java b/src/main/java/org/traccar/protocol/VisiontekProtocolDecoder.java
index c4787bda2..9ab871bfe 100644
--- a/src/main/java/org/traccar/protocol/VisiontekProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/VisiontekProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/VltProtocol.java b/src/main/java/org/traccar/protocol/VltProtocol.java
new file mode 100644
index 000000000..005cd8ffb
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/VltProtocol.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
+
+public class VltProtocol extends BaseProtocol {
+
+ @Inject
+ public VltProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new HttpResponseEncoder());
+ pipeline.addLast(new HttpRequestDecoder());
+ pipeline.addLast(new HttpObjectAggregator(65535));
+ pipeline.addLast(new VltProtocolDecoder(VltProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/VltProtocolDecoder.java b/src/main/java/org/traccar/protocol/VltProtocolDecoder.java
new file mode 100644
index 000000000..01c0563f5
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/VltProtocolDecoder.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.protocol;
+
+import io.netty.channel.Channel;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.QueryStringDecoder;
+import org.traccar.BaseHttpProtocolDecoder;
+import org.traccar.Protocol;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
+import org.traccar.model.CellTower;
+import org.traccar.model.Network;
+import org.traccar.model.Position;
+import org.traccar.session.DeviceSession;
+
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class VltProtocolDecoder extends BaseHttpProtocolDecoder {
+
+ public VltProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .number("(dd)") // alert id
+ .expression("([HL])") // history
+ .number("([01])") // validity
+ .number("(dd)(dd)(dd)") // date (ddmmyy)
+ .number("(dd)(dd)(dd)") // time (hhmmss)
+ .number("(d{3}.d{6})([NS])") // latitude
+ .number("(d{3}.d{6})([EW])") // longitude
+ .number("(d{3})") // mcc
+ .expression("(x*[0-9]+)") // mnc
+ .number("(x{4})") // lac
+ .number("(d{9})") // cid
+ .number("(d{3}.d{2})") // speed
+ .number("(d{3}.d{2})") // course
+ .number("(d{2})") // satellites
+ .number("(d{2})") // hdop
+ .number("(d{2})") // rssi
+ .number("([01])") // ignition
+ .number("([01])") // charging
+ .expression("([HMS])") // vehicle mode
+ .compile();
+
+ private Position decodePosition(DeviceSession deviceSession, String sentence) {
+
+ Parser parser = new Parser(PATTERN, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.set(Position.KEY_EVENT, parser.nextInt());
+ position.set(Position.KEY_ARCHIVE, parser.next().equals("H") ? true : null);
+
+ position.setValid(parser.nextInt() > 0);
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+
+ int mcc = parser.nextInt();
+ int mnc = Integer.parseInt(parser.next().replaceAll("x", ""));
+ int lac = parser.nextHexInt();
+ int cid = parser.nextInt();
+
+ position.setSpeed(parser.nextDouble());
+ position.setCourse(parser.nextDouble());
+
+ position.set(Position.KEY_SATELLITES, parser.nextInt());
+ position.set(Position.KEY_HDOP, parser.nextInt());
+
+ position.setNetwork(new Network(CellTower.from(mcc, mnc, lac, cid, parser.nextInt())));
+
+ position.set(Position.KEY_IGNITION, parser.nextInt() > 0);
+ position.set(Position.KEY_CHARGE, parser.nextInt() > 0);
+ position.set(Position.KEY_MOTION, parser.next().equals("M"));
+
+ return position;
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ FullHttpRequest request = (FullHttpRequest) msg;
+ QueryStringDecoder decoder = new QueryStringDecoder(
+ request.content().toString(StandardCharsets.US_ASCII), false);
+ String sentence = decoder.parameters().get("vltdata").iterator().next();
+
+ int index = 0;
+ String type = sentence.substring(index, index += 3);
+ String imei = sentence.substring(index, index += 15);
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
+ if (deviceSession == null) {
+ sendResponse(channel, HttpResponseStatus.BAD_REQUEST);
+ return null;
+ }
+
+ sendResponse(channel, HttpResponseStatus.OK);
+
+ switch (type) {
+ case "NRM":
+ return decodePosition(deviceSession, sentence.substring(3 + 15));
+ case "BTH":
+ List<Position> positions = new LinkedList<>();
+ int count = Integer.parseInt(sentence.substring(index, index += 3));
+ for (int i = 0; i < count; i++) {
+ positions.add(decodePosition(deviceSession, sentence.substring(index, index += 78)));
+ }
+ return positions;
+ default:
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/VnetProtocol.java b/src/main/java/org/traccar/protocol/VnetProtocol.java
index 0fed30e13..6ccc54483 100644
--- a/src/main/java/org/traccar/protocol/VnetProtocol.java
+++ b/src/main/java/org/traccar/protocol/VnetProtocol.java
@@ -19,15 +19,19 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import java.nio.ByteOrder;
+import jakarta.inject.Inject;
+
public class VnetProtocol extends BaseProtocol {
- public VnetProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public VnetProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1500, 4, 2, 12, 0, true));
pipeline.addLast(new VnetProtocolDecoder(VnetProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/VnetProtocolDecoder.java b/src/main/java/org/traccar/protocol/VnetProtocolDecoder.java
index 1ee00bd3f..048c89e1e 100644
--- a/src/main/java/org/traccar/protocol/VnetProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/VnetProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BcdUtil;
diff --git a/src/main/java/org/traccar/protocol/Vt200Protocol.java b/src/main/java/org/traccar/protocol/Vt200Protocol.java
index 2a9ef6ab5..97e64b74f 100644
--- a/src/main/java/org/traccar/protocol/Vt200Protocol.java
+++ b/src/main/java/org/traccar/protocol/Vt200Protocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Vt200Protocol extends BaseProtocol {
- public Vt200Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Vt200Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new Vt200FrameDecoder());
pipeline.addLast(new Vt200ProtocolDecoder(Vt200Protocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java
index 84ad09caa..1ad15f39c 100644
--- a/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Vt200ProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.BcdUtil;
import org.traccar.helper.BitUtil;
@@ -123,7 +123,7 @@ public class Vt200ProtocolDecoder extends BaseProtocolDecoder {
position.set("tripStart", decodeDate(buf).getTime());
position.set("tripEnd", decodeDate(buf).getTime());
- position.set("drivingTime", buf.readUnsignedShort());
+ position.set(Position.KEY_DRIVING_TIME, buf.readUnsignedShort());
position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedInt());
position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedInt());
diff --git a/src/main/java/org/traccar/protocol/VtfmsProtocol.java b/src/main/java/org/traccar/protocol/VtfmsProtocol.java
index 2826a86e6..91453c413 100644
--- a/src/main/java/org/traccar/protocol/VtfmsProtocol.java
+++ b/src/main/java/org/traccar/protocol/VtfmsProtocol.java
@@ -15,26 +15,29 @@
*/
package org.traccar.protocol;
+import io.netty.handler.codec.string.StringDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
-import io.netty.handler.codec.string.StringDecoder;
+import jakarta.inject.Inject;
public class VtfmsProtocol extends BaseProtocol {
- public VtfmsProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public VtfmsProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new VtfmsFrameDecoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new VtfmsProtocolDecoder(VtfmsProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringDecoder());
pipeline.addLast(new VtfmsProtocolDecoder(VtfmsProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/VtfmsProtocolDecoder.java b/src/main/java/org/traccar/protocol/VtfmsProtocolDecoder.java
index 17fac4311..bf0cdcb51 100644
--- a/src/main/java/org/traccar/protocol/VtfmsProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/VtfmsProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/WatchFrameDecoder.java b/src/main/java/org/traccar/protocol/WatchFrameDecoder.java
index f99bd52e2..9dfae8726 100644
--- a/src/main/java/org/traccar/protocol/WatchFrameDecoder.java
+++ b/src/main/java/org/traccar/protocol/WatchFrameDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,7 +27,26 @@ public class WatchFrameDecoder extends BaseFrameDecoder {
protected Object decode(
ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception {
- int endIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ']') + 1;
+ int brackets = 0;
+ int endIndex = -1;
+ for (int i = buf.readerIndex(); i < buf.writerIndex(); i++) {
+ byte b = buf.getByte(i);
+ switch (b) {
+ case '[':
+ brackets += 1;
+ break;
+ case ']':
+ brackets -= 1;
+ break;
+ default:
+ break;
+ }
+ if (brackets == 0 && i > buf.readerIndex()) {
+ endIndex = i + 1;
+ break;
+ }
+ }
+
if (endIndex > 0) {
ByteBuf frame = Unpooled.buffer();
while (buf.readerIndex() < endIndex) {
diff --git a/src/main/java/org/traccar/protocol/WatchProtocol.java b/src/main/java/org/traccar/protocol/WatchProtocol.java
index 6dc3bf9fb..aee70b6ec 100644
--- a/src/main/java/org/traccar/protocol/WatchProtocol.java
+++ b/src/main/java/org/traccar/protocol/WatchProtocol.java
@@ -18,11 +18,15 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
+import jakarta.inject.Inject;
+
public class WatchProtocol extends BaseProtocol {
- public WatchProtocol() {
+ @Inject
+ public WatchProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_POSITION_SINGLE,
@@ -40,9 +44,9 @@ public class WatchProtocol extends BaseProtocol {
Command.TYPE_VOICE_MESSAGE,
Command.TYPE_SET_TIMEZONE,
Command.TYPE_SET_INDICATOR);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new WatchFrameDecoder());
pipeline.addLast(new WatchProtocolEncoder(WatchProtocol.this));
pipeline.addLast(new WatchProtocolDecoder(WatchProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java b/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java
index 4ab7875b7..b586f4e92 100644
--- a/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,14 +18,13 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.helper.StringUtil;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
+import org.traccar.helper.BufferUtil;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
import org.traccar.helper.UnitsConverter;
@@ -41,7 +40,7 @@ import java.util.regex.Pattern;
public class WatchProtocolDecoder extends BaseProtocolDecoder {
- private static final Logger LOGGER = LoggerFactory.getLogger(WatchProtocolDecoder.class);
+ private ByteBuf audio;
public WatchProtocolDecoder(Protocol protocol) {
super(protocol);
@@ -52,7 +51,7 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
.number("(dd)(dd)(dd),") // time (hhmmss)
.expression("([AV]),") // validity
.number(" *(-?d+.d+),") // latitude
- .expression("([NS]),")
+ .expression("([NS])?,")
.number(" *(-?d+.d+),") // longitude
.expression("([EW])?,")
.number("(d+.?d*),") // speed
@@ -141,36 +140,45 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
String[] values = parser.next().split(",");
int index = 0;
- Network network = new Network();
+ if (values.length < 4 || !StringUtil.containsHex(values[index + 3])) {
- int cellCount = Integer.parseInt(values[index++]);
- index += 1; // timing advance
- int mcc = !values[index].isEmpty() ? Integer.parseInt(values[index++]) : 0;
- int mnc = !values[index].isEmpty() ? Integer.parseInt(values[index++]) : 0;
+ Network network = new Network();
- for (int i = 0; i < cellCount; i++) {
- int lac = Integer.parseInt(values[index++]);
- int cid = Integer.parseInt(values[index++]);
- String rssi = values[index++];
- if (!rssi.isEmpty()) {
- network.addCellTower(CellTower.from(mcc, mnc, lac, cid, Integer.parseInt(rssi)));
- } else {
- network.addCellTower(CellTower.from(mcc, mnc, lac, cid));
+ int cellCount = Integer.parseInt(values[index++]);
+ if (cellCount > 0) {
+ index += 1; // timing advance
+ int mcc = !values[index].isEmpty() ? Integer.parseInt(values[index++]) : 0;
+ int mnc = !values[index].isEmpty() ? Integer.parseInt(values[index++]) : 0;
+
+ for (int i = 0; i < cellCount; i++) {
+ int lac = Integer.parseInt(values[index], StringUtil.containsHex(values[index++]) ? 16 : 10);
+ int cid = Integer.parseInt(values[index], StringUtil.containsHex(values[index++]) ? 16 : 10);
+ String rssi = values[index++];
+ if (!rssi.isEmpty()) {
+ network.addCellTower(CellTower.from(mcc, mnc, lac, cid, Integer.parseInt(rssi)));
+ } else {
+ network.addCellTower(CellTower.from(mcc, mnc, lac, cid));
+ }
+ }
}
- }
- if (index < values.length && !values[index].isEmpty()) {
- int wifiCount = Integer.parseInt(values[index++]);
+ if (index < values.length && !values[index].isEmpty()) {
+ int wifiCount = Integer.parseInt(values[index++]);
- for (int i = 0; i < wifiCount; i++) {
- index += 1; // wifi name
- network.addWifiAccessPoint(WifiAccessPoint.from(
- values[index++], Integer.parseInt(values[index++])));
+ for (int i = 0; i < wifiCount; i++) {
+ index += 1; // wifi name
+ String macAddress = values[index++];
+ String rssi = values[index++];
+ if (!macAddress.isEmpty() && !macAddress.equals("0") && !rssi.isEmpty()) {
+ network.addWifiAccessPoint(WifiAccessPoint.from(macAddress, Integer.parseInt(rssi)));
+ }
+ }
+ }
+
+ if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) {
+ position.setNetwork(network);
}
- }
- if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) {
- position.setNetwork(network);
}
return position;
@@ -260,6 +268,9 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
Position position = decodePosition(deviceSession, buf.toString(StandardCharsets.US_ASCII));
if (type.startsWith("AL")) {
+ if (position != null && !position.hasAttribute(Position.KEY_ALARM)) {
+ position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
+ }
sendResponse(channel, id, index, "AL");
}
@@ -273,7 +284,9 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
|| type.equalsIgnoreCase("HEART")
|| type.equalsIgnoreCase("BLOOD")
|| type.equalsIgnoreCase("BPHRT")
- || type.equalsIgnoreCase("btemp2")) {
+ || type.equalsIgnoreCase("TEMP")
+ || type.equalsIgnoreCase("btemp2")
+ || type.equalsIgnoreCase("oxygen")) {
if (buf.isReadable()) {
@@ -285,10 +298,14 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
String[] values = buf.toString(StandardCharsets.US_ASCII).split(",");
int valueIndex = 0;
- if (type.equalsIgnoreCase("btemp2")) {
+ if (type.equalsIgnoreCase("TEMP")) {
+ position.set(Position.PREFIX_TEMP + 1, Double.parseDouble(values[valueIndex]));
+ } else if (type.equalsIgnoreCase("btemp2")) {
if (Integer.parseInt(values[valueIndex++]) > 0) {
position.set(Position.PREFIX_TEMP + 1, Double.parseDouble(values[valueIndex]));
}
+ } else if (type.equalsIgnoreCase("oxygen")) {
+ position.set("bloodOxygen", Integer.parseInt(values[++valueIndex]));
} else {
if (type.equalsIgnoreCase("BPHRT") || type.equalsIgnoreCase("BLOOD")) {
position.set("pressureHigh", values[valueIndex++]);
@@ -312,17 +329,41 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
int timeIndex = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) ',');
buf.readerIndex(timeIndex + 12 + 2);
- position.set(Position.KEY_IMAGE, Context.getMediaManager().writeFile(id, buf, "jpg"));
+ position.set(Position.KEY_IMAGE, writeMediaFile(id, buf, "jpg"));
return position;
+ } else if (type.equals("JXTK")) {
+
+ int dataIndex = BufferUtil.indexOf(buf, buf.readerIndex(), buf.writerIndex(), (byte) ',', 4) + 1;
+ String[] values = buf.readCharSequence(
+ dataIndex - buf.readerIndex(), StandardCharsets.US_ASCII).toString().split(",");
+
+ int current = Integer.parseInt(values[2]);
+ int total = Integer.parseInt(values[3]);
+
+ if (audio == null) {
+ audio = Unpooled.buffer();
+ }
+ audio.writeBytes(buf);
+
+ sendResponse(channel, id, index, "JXTKR,1");
+
+ if (current < total) {
+ return null;
+ } else {
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+ getLastLocation(position, null);
+ position.set(Position.KEY_AUDIO, writeMediaFile(id, audio, "amr"));
+ audio.release();
+ audio = null;
+ return position;
+ }
+
} else if (type.equals("TK")) {
if (buf.readableBytes() == 1) {
- byte result = buf.readByte();
- if (result != '1') {
- LOGGER.warn(type + "," + result);
- }
return null;
}
@@ -331,7 +372,7 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
getLastLocation(position, null);
- position.set(Position.KEY_AUDIO, Context.getMediaManager().writeFile(id, buf, "amr"));
+ position.set(Position.KEY_AUDIO, writeMediaFile(id, buf, "amr"));
return position;
diff --git a/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java b/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java
index f1904ea4d..14ebe2852 100644
--- a/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/WatchProtocolEncoder.java
@@ -67,6 +67,9 @@ public class WatchProtocolEncoder extends StringProtocolEncoder implements Strin
if (decoder != null) {
hasIndex = decoder.getHasIndex();
manufacturer = decoder.getManufacturer();
+ if (manufacturer.equals("3G")) {
+ manufacturer = "SG";
+ }
}
}
diff --git a/src/main/java/org/traccar/protocol/WialonProtocol.java b/src/main/java/org/traccar/protocol/WialonProtocol.java
index cb6ea5319..84033132d 100644
--- a/src/main/java/org/traccar/protocol/WialonProtocol.java
+++ b/src/main/java/org/traccar/protocol/WialonProtocol.java
@@ -15,32 +15,34 @@
*/
package org.traccar.protocol;
+import io.netty.handler.codec.LineBasedFrameDecoder;
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
-import org.traccar.Context;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Command;
-import io.netty.handler.codec.LineBasedFrameDecoder;
-import io.netty.handler.codec.string.StringDecoder;
-import io.netty.handler.codec.string.StringEncoder;
-
import java.nio.charset.StandardCharsets;
+import jakarta.inject.Inject;
+
public class WialonProtocol extends BaseProtocol {
- public WialonProtocol() {
+ @Inject
+ public WialonProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_REBOOT_DEVICE,
Command.TYPE_SEND_USSD,
Command.TYPE_IDENTIFICATION,
Command.TYPE_OUTPUT_CONTROL);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(4 * 1024));
- boolean utf8 = Context.getConfig().getBoolean(Keys.PROTOCOL_UTF8.withPrefix(getName()));
+ boolean utf8 = config.getBoolean(Keys.PROTOCOL_UTF8.withPrefix(getName()));
if (utf8) {
pipeline.addLast(new StringEncoder(StandardCharsets.UTF_8));
pipeline.addLast(new StringDecoder(StandardCharsets.UTF_8));
@@ -52,11 +54,11 @@ public class WialonProtocol extends BaseProtocol {
pipeline.addLast(new WialonProtocolDecoder(WialonProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(4 * 1024));
- boolean utf8 = Context.getConfig().getBoolean(Keys.PROTOCOL_UTF8.withPrefix(getName()));
+ boolean utf8 = config.getBoolean(Keys.PROTOCOL_UTF8.withPrefix(getName()));
if (utf8) {
pipeline.addLast(new StringEncoder(StandardCharsets.UTF_8));
pipeline.addLast(new StringDecoder(StandardCharsets.UTF_8));
diff --git a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java
index 19d9dd6c8..4d1b34dba 100644
--- a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
@@ -39,7 +39,7 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder {
}
private static final Pattern PATTERN_ANY = new PatternBuilder()
- .expression("([^#]*)?") // imei
+ .expression("([^#]+)?") // imei
.text("#") // start byte
.expression("([^#]+)") // type
.text("#") // separator
@@ -63,8 +63,9 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder {
.number("(?:NA|(d+));") // outputs
.expression("(?:NA|([^;]*));") // adc
.expression("(?:NA|([^;]*));") // ibutton
- .expression("(?:NA|(.*))") // params
+ .expression("(?:NA|([^;]*))") // params
.groupEnd("?")
+ .any()
.compile();
private void sendResponse(Channel channel, SocketAddress remoteAddress, String type, Integer number) {
@@ -101,7 +102,7 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder {
position.setTime(new Date());
}
- if (parser.hasNext(9)) {
+ if (parser.hasNextAny(9)) {
position.setLatitude(parser.nextCoordinate());
position.setLongitude(parser.nextCoordinate());
position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0)));
@@ -135,10 +136,22 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder {
for (String param : values) {
Matcher paramParser = Pattern.compile("(.*):[1-3]:(.*)").matcher(param);
if (paramParser.matches()) {
+ String key = paramParser.group(1).toLowerCase();
+ String value = paramParser.group(2);
try {
- position.set(paramParser.group(1).toLowerCase(), Double.parseDouble(paramParser.group(2)));
+ if (key.equals("accuracy")) {
+ position.setAccuracy(Double.parseDouble(value));
+ } else {
+ position.set(key, Double.parseDouble(value));
+ }
} catch (NumberFormatException e) {
- position.set(paramParser.group(1).toLowerCase(), paramParser.group(2));
+ if (value.equalsIgnoreCase("true")) {
+ position.set(key, true);
+ } else if (value.equalsIgnoreCase("false")) {
+ position.set(key, false);
+ } else {
+ position.set(key, value);
+ }
}
}
}
diff --git a/src/main/java/org/traccar/protocol/WliProtocol.java b/src/main/java/org/traccar/protocol/WliProtocol.java
index c10ebf505..5b9ebb520 100644
--- a/src/main/java/org/traccar/protocol/WliProtocol.java
+++ b/src/main/java/org/traccar/protocol/WliProtocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class WliProtocol extends BaseProtocol {
- public WliProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public WliProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new WliFrameDecoder());
pipeline.addLast(new WliProtocolDecoder(WliProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/WliProtocolDecoder.java b/src/main/java/org/traccar/protocol/WliProtocolDecoder.java
index 0e2a0a65e..ec1c4d17a 100644
--- a/src/main/java/org/traccar/protocol/WliProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/WliProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2020 - 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.
@@ -18,10 +18,12 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.UnitsConverter;
+import org.traccar.model.CellTower;
+import org.traccar.model.Network;
import org.traccar.model.Position;
import java.net.SocketAddress;
@@ -41,9 +43,9 @@ public class WliProtocolDecoder extends BaseProtocolDecoder {
ByteBuf buf = (ByteBuf) msg;
buf.readUnsignedByte(); // header
- int type = buf.readUnsignedByte();
+ int clazz = buf.readUnsignedByte();
- if (type == '1') {
+ if (clazz == '1') {
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
if (deviceSession == null) {
@@ -53,11 +55,13 @@ public class WliProtocolDecoder extends BaseProtocolDecoder {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
+ CellTower cellTower = new CellTower();
+
position.set(Position.KEY_INDEX, buf.readUnsignedShort());
buf.readUnsignedShort(); // length
buf.readUnsignedShort(); // checksum
- buf.readUnsignedByte(); // application message type
+ int type = buf.readUnsignedByte();
buf.readUnsignedByte(); // delimiter
while (buf.readableBytes() > 1) {
@@ -95,18 +99,56 @@ public class WliProtocolDecoder extends BaseProtocolDecoder {
String value = buf.readCharSequence(
endIndex - buf.readerIndex(), StandardCharsets.US_ASCII).toString();
- switch (fieldNumber) {
- case 246:
- String[] values = value.split(",");
- position.set(Position.KEY_POWER, Integer.parseInt(values[2]) * 0.01);
- position.set(Position.KEY_BATTERY, Integer.parseInt(values[3]) * 0.01);
+ int networkFieldsOffset;
+ switch (type) {
+ case 0xE4:
+ networkFieldsOffset = 10;
+ break;
+ case 0xCB:
+ networkFieldsOffset = 80;
break;
- case 255:
- position.setDeviceTime(new Date(Long.parseLong(value) * 1000));
+ case 0x1E:
+ networkFieldsOffset = 182;
break;
+ case 0xC9:
default:
+ networkFieldsOffset = 35;
break;
}
+ if (fieldNumber - networkFieldsOffset >= 0 && fieldNumber - networkFieldsOffset < 10) {
+ switch (fieldNumber - networkFieldsOffset) {
+ case 0:
+ cellTower.setMobileCountryCode(Integer.parseInt(value));
+ break;
+ case 1:
+ cellTower.setMobileNetworkCode(Integer.parseInt(value));
+ break;
+ case 2:
+ cellTower.setLocationAreaCode(Integer.parseInt(value));
+ break;
+ case 3:
+ cellTower.setCellId(Long.parseLong(value));
+ break;
+ case 4:
+ cellTower.setSignalStrength(Integer.parseInt(value));
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (fieldNumber) {
+ case 246:
+ String[] values = value.split(",");
+ position.set(Position.KEY_POWER, Integer.parseInt(values[2]) * 0.01);
+ position.set(Position.KEY_BATTERY, Integer.parseInt(values[3]) * 0.01);
+ break;
+ case 255:
+ position.setDeviceTime(new Date(Long.parseLong(value) * 1000));
+ break;
+ default:
+ break;
+ }
+ }
}
@@ -114,13 +156,21 @@ public class WliProtocolDecoder extends BaseProtocolDecoder {
}
+ if (type == 0xE4) {
+ getLastLocation(position, position.getDeviceTime());
+ }
+
+ if (cellTower.getCellId() != null) {
+ position.setNetwork(new Network(cellTower));
+ }
+
if (!position.getValid()) {
getLastLocation(position, position.getDeviceTime());
}
return position;
- } else if (type == '2') {
+ } else if (clazz == '2') {
String id = buf.toString(buf.readerIndex(), buf.readableBytes() - 1, StandardCharsets.US_ASCII);
getDeviceSession(channel, remoteAddress, id.substring("wli:".length()));
diff --git a/src/main/java/org/traccar/protocol/WondexProtocol.java b/src/main/java/org/traccar/protocol/WondexProtocol.java
index 6401fde85..e27b8e2bb 100644
--- a/src/main/java/org/traccar/protocol/WondexProtocol.java
+++ b/src/main/java/org/traccar/protocol/WondexProtocol.java
@@ -15,16 +15,19 @@
*/
package org.traccar.protocol;
+import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
-import io.netty.handler.codec.string.StringEncoder;
+import jakarta.inject.Inject;
public class WondexProtocol extends BaseProtocol {
- public WondexProtocol() {
+ @Inject
+ public WondexProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_GET_DEVICE_STATUS,
Command.TYPE_GET_MODEM_STATUS,
@@ -40,18 +43,18 @@ public class WondexProtocol extends BaseProtocol {
Command.TYPE_POSITION_SINGLE,
Command.TYPE_GET_VERSION,
Command.TYPE_IDENTIFICATION);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new WondexFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new WondexProtocolEncoder(WondexProtocol.this));
pipeline.addLast(new WondexProtocolDecoder(WondexProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new WondexProtocolEncoder(WondexProtocol.this));
pipeline.addLast(new WondexProtocolDecoder(WondexProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/WondexProtocolDecoder.java b/src/main/java/org/traccar/protocol/WondexProtocolDecoder.java
index b85ae2656..46aa65a5d 100644
--- a/src/main/java/org/traccar/protocol/WondexProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/WondexProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 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.
@@ -18,7 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
@@ -74,6 +74,9 @@ public class WondexProtocolDecoder extends BaseProtocolDecoder {
|| buf.toString(StandardCharsets.US_ASCII).startsWith("$MSG:")) {
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress);
+ if (deviceSession == null) {
+ return null;
+ }
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
@@ -89,12 +92,12 @@ public class WondexProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- Position position = new Position(getProtocolName());
-
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
if (deviceSession == null) {
return null;
}
+
+ Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
position.setTime(parser.nextDateTime());
diff --git a/src/main/java/org/traccar/protocol/WristbandProtocol.java b/src/main/java/org/traccar/protocol/WristbandProtocol.java
index 1e5ef2c01..117daf8cf 100644
--- a/src/main/java/org/traccar/protocol/WristbandProtocol.java
+++ b/src/main/java/org/traccar/protocol/WristbandProtocol.java
@@ -19,13 +19,17 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class WristbandProtocol extends BaseProtocol {
- public WristbandProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public WristbandProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 3, 2, 3, 0));
pipeline.addLast(new WristbandProtocolDecoder(WristbandProtocol.this));
}
diff --git a/src/main/java/org/traccar/protocol/WristbandProtocolDecoder.java b/src/main/java/org/traccar/protocol/WristbandProtocolDecoder.java
index 58b5784d0..323992ddd 100644
--- a/src/main/java/org/traccar/protocol/WristbandProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/WristbandProtocolDecoder.java
@@ -19,7 +19,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/Xexun2FrameEncoder.java b/src/main/java/org/traccar/protocol/Xexun2FrameEncoder.java
new file mode 100644
index 000000000..52d43c36c
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/Xexun2FrameEncoder.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2022 Stefan Clark (stefan@stefanclark.co.uk)
+ *
+ * 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.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.MessageToByteEncoder;
+
+public class Xexun2FrameEncoder extends MessageToByteEncoder<ByteBuf> {
+
+ @Override
+ protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) {
+ out.writeBytes(msg.readBytes(2));
+
+ while (msg.readableBytes() > 2) {
+ int b = msg.readUnsignedByte();
+ if (b == 0xfa && msg.isReadable() && msg.getUnsignedByte(msg.readerIndex()) == 0xaf) {
+ msg.readUnsignedByte();
+ out.writeByte(0xfb);
+ out.writeByte(0xbf);
+ out.writeByte(0x01);
+ } else if (b == 0xfb && msg.isReadable() && msg.getUnsignedByte(msg.readerIndex()) == 0xbf) {
+ msg.readUnsignedByte();
+ out.writeByte(0xfb);
+ out.writeByte(0xbf);
+ out.writeByte(0x02);
+ } else {
+ out.writeByte(b);
+ }
+ }
+
+ out.writeBytes(msg.readBytes(2));
+
+ }
+}
diff --git a/src/main/java/org/traccar/protocol/Xexun2Protocol.java b/src/main/java/org/traccar/protocol/Xexun2Protocol.java
index 265841c77..9dd517cfa 100644
--- a/src/main/java/org/traccar/protocol/Xexun2Protocol.java
+++ b/src/main/java/org/traccar/protocol/Xexun2Protocol.java
@@ -18,15 +18,27 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+import org.traccar.model.Command;
+
+import jakarta.inject.Inject;
public class Xexun2Protocol extends BaseProtocol {
- public Xexun2Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Xexun2Protocol(Config config) {
+ setSupportedDataCommands(
+ Command.TYPE_CUSTOM,
+ Command.TYPE_POSITION_PERIODIC,
+ Command.TYPE_POWER_OFF,
+ Command.TYPE_REBOOT_DEVICE);
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new Xexun2FrameEncoder());
pipeline.addLast(new Xexun2FrameDecoder());
pipeline.addLast(new Xexun2ProtocolDecoder(Xexun2Protocol.this));
+ pipeline.addLast(new Xexun2ProtocolEncoder(Xexun2Protocol.this));
}
});
}
diff --git a/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java
index 766a3f05b..0e3c44e12 100644
--- a/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java
@@ -20,10 +20,11 @@ import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.BitUtil;
+import org.traccar.helper.Checksum;
import org.traccar.helper.UnitsConverter;
import org.traccar.model.CellTower;
import org.traccar.model.Network;
@@ -41,13 +42,14 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
+ public static final int FLAG = 0xfaaf;
+ public static final int MSG_COMMAND = 0x07;
public static final int MSG_POSITION = 0x14;
private void sendResponse(Channel channel, int type, int index, ByteBuf imei) {
if (channel != null) {
ByteBuf response = Unpooled.buffer();
- response.writeByte(0xfa);
- response.writeByte(0xaf);
+ response.writeShort(FLAG);
response.writeShort(type);
response.writeShort(index);
@@ -56,8 +58,7 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder {
response.writeShort(0xfffe); // checksum
response.writeByte(1); // response
- response.writeByte(0xfa);
- response.writeByte(0xaf);
+ response.writeShort(FLAG);
channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress()));
}
@@ -67,6 +68,9 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder {
if (BitUtil.check(value, 0)) {
return Position.ALARM_SOS;
}
+ if (BitUtil.check(value, 1)) {
+ return Position.ALARM_REMOVING;
+ }
if (BitUtil.check(value, 15)) {
return Position.ALARM_FALL_DOWN;
}
@@ -96,10 +100,16 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- sendResponse(channel, type, index, imei);
+ int payloadSize = buf.readUnsignedShort() & 0x03ff;
+ int checksum = buf.readUnsignedShort();
+
+ if (checksum != Checksum.ip(buf.nioBuffer(buf.readerIndex(), payloadSize))) {
+ return null;
+ }
- buf.readUnsignedShort(); // attributes
- buf.readUnsignedShort(); // checksum
+ if (type != MSG_COMMAND) {
+ sendResponse(channel, type, index, imei);
+ }
if (type == MSG_POSITION) {
List<Integer> lengths = new ArrayList<>();
@@ -146,7 +156,7 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder {
for (int j = 0; j < wifiCount; j++) {
String mac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:");
network.addWifiAccessPoint(WifiAccessPoint.from(
- mac.substring(0, mac.length() - 1), buf.readUnsignedByte()));
+ mac.substring(0, mac.length() - 1), buf.readByte()));
}
}
if (BitUtil.check(positionMask, 2)) {
@@ -154,7 +164,7 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder {
for (int j = 0; j < cellCount; j++) {
network.addCellTower(CellTower.from(
buf.readUnsignedShort(), buf.readUnsignedShort(),
- buf.readInt(), buf.readUnsignedInt(), buf.readUnsignedByte()));
+ buf.readInt(), buf.readUnsignedInt(), buf.readByte()));
}
}
if (network.getWifiAccessPoints() != null || network.getCellTowers() != null) {
@@ -173,7 +183,25 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
position.setLongitude(convertCoordinate(buf.readDouble()));
position.setLatitude(convertCoordinate(buf.readDouble()));
-
+ }
+ if (BitUtil.check(positionMask, 7)) {
+ int dataLength = buf.readUnsignedShort();
+ if (dataLength > 0) {
+ int dataType = buf.readUnsignedByte();
+ int dataEndIndex = buf.readerIndex() + buf.readUnsignedShort();
+ if (dataType == 'G') {
+ position.setFixTime(position.getDeviceTime());
+ position.setLongitude(convertCoordinate(buf.readDouble()));
+ position.setLatitude(convertCoordinate(buf.readDouble()));
+ position.setValid(buf.readUnsignedByte() > 0);
+ position.set(Position.KEY_SATELLITES, buf.readUnsignedByte());
+ buf.readUnsignedByte(); // satellite signal-to-noise ratio
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedShort() * 0.1));
+ position.setCourse(buf.readUnsignedShort() * 0.1);
+ position.setAltitude(buf.readFloat());
+ }
+ buf.readerIndex(dataEndIndex);
+ }
}
}
if (BitUtil.check(mask, 3)) {
diff --git a/src/main/java/org/traccar/protocol/Xexun2ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Xexun2ProtocolEncoder.java
new file mode 100644
index 000000000..8f3fa5672
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/Xexun2ProtocolEncoder.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2022 Stefan Clark (stefan@stefanclark.co.uk)
+ *
+ * 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.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import org.traccar.BaseProtocolEncoder;
+import org.traccar.helper.Checksum;
+import org.traccar.helper.DataConverter;
+import org.traccar.model.Command;
+import org.traccar.Protocol;
+
+import java.nio.charset.StandardCharsets;
+
+public class Xexun2ProtocolEncoder extends BaseProtocolEncoder {
+
+ public Xexun2ProtocolEncoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private static ByteBuf encodeContent(String uniqueId, String content) {
+ ByteBuf buf = Unpooled.buffer();
+
+ ByteBuf message = Unpooled.copiedBuffer(content.getBytes(StandardCharsets.US_ASCII));
+
+ buf.writeShort(Xexun2ProtocolDecoder.FLAG);
+ buf.writeShort(Xexun2ProtocolDecoder.MSG_COMMAND);
+ buf.writeShort(1); // index
+ buf.writeBytes(DataConverter.parseHex(uniqueId + "0"));
+ buf.writeShort(message.readableBytes());
+ buf.writeShort(Checksum.ip(message.nioBuffer()));
+ buf.writeBytes(message);
+ buf.writeShort(Xexun2ProtocolDecoder.FLAG);
+
+ return buf;
+ }
+
+ @Override
+ protected Object encodeCommand(Command command) {
+ String uniqueId = getUniqueId(command.getDeviceId());
+
+ switch (command.getType()) {
+ case Command.TYPE_CUSTOM:
+ return encodeContent(uniqueId, command.getString(Command.KEY_DATA));
+ case Command.TYPE_POSITION_PERIODIC:
+ return encodeContent(uniqueId,
+ String.format("tracking_send=%1$d,%1$d", command.getInteger(Command.KEY_FREQUENCY)));
+ case Command.TYPE_POWER_OFF:
+ return encodeContent(uniqueId, "of=1");
+ case Command.TYPE_REBOOT_DEVICE:
+ return encodeContent(uniqueId, "reset");
+ default:
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/XexunProtocol.java b/src/main/java/org/traccar/protocol/XexunProtocol.java
index b83c4e445..e76e47d19 100644
--- a/src/main/java/org/traccar/protocol/XexunProtocol.java
+++ b/src/main/java/org/traccar/protocol/XexunProtocol.java
@@ -15,27 +15,29 @@
*/
package org.traccar.protocol;
+import io.netty.handler.codec.LineBasedFrameDecoder;
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
-import org.traccar.Context;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Command;
-import io.netty.handler.codec.LineBasedFrameDecoder;
-import io.netty.handler.codec.string.StringDecoder;
-import io.netty.handler.codec.string.StringEncoder;
+import jakarta.inject.Inject;
public class XexunProtocol extends BaseProtocol {
- public XexunProtocol() {
+ @Inject
+ public XexunProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_ENGINE_STOP,
Command.TYPE_ENGINE_RESUME);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
- boolean full = Context.getConfig().getBoolean(Keys.PROTOCOL_EXTENDED.withPrefix(getName()));
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ boolean full = config.getBoolean(Keys.PROTOCOL_EXTENDED.withPrefix(getName()));
if (full) {
pipeline.addLast(new LineBasedFrameDecoder(1024)); // tracker bug \n\r
} else {
diff --git a/src/main/java/org/traccar/protocol/XexunProtocolDecoder.java b/src/main/java/org/traccar/protocol/XexunProtocolDecoder.java
index 73d386477..e41d467d5 100644
--- a/src/main/java/org/traccar/protocol/XexunProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/XexunProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/protocol/XirgoProtocol.java b/src/main/java/org/traccar/protocol/XirgoProtocol.java
index 1be5b6c4b..7e14c6842 100644
--- a/src/main/java/org/traccar/protocol/XirgoProtocol.java
+++ b/src/main/java/org/traccar/protocol/XirgoProtocol.java
@@ -15,23 +15,26 @@
*/
package org.traccar.protocol;
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.CharacterDelimiterFrameDecoder;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
-import io.netty.handler.codec.string.StringDecoder;
-import io.netty.handler.codec.string.StringEncoder;
+import jakarta.inject.Inject;
public class XirgoProtocol extends BaseProtocol {
- public XirgoProtocol() {
+ @Inject
+ public XirgoProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_OUTPUT_CONTROL);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, "##"));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
@@ -39,9 +42,9 @@ public class XirgoProtocol extends BaseProtocol {
pipeline.addLast(new XirgoProtocolDecoder(XirgoProtocol.this));
}
});
- addServer(new TrackerServer(true, getName()) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new XirgoProtocolEncoder(XirgoProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/XirgoProtocolDecoder.java b/src/main/java/org/traccar/protocol/XirgoProtocolDecoder.java
index 630fe5aed..220c28054 100644
--- a/src/main/java/org/traccar/protocol/XirgoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/XirgoProtocolDecoder.java
@@ -18,8 +18,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.config.Keys;
@@ -40,7 +39,11 @@ public class XirgoProtocolDecoder extends BaseProtocolDecoder {
public XirgoProtocolDecoder(Protocol protocol) {
super(protocol);
- form = Context.getConfig().getString(Keys.PROTOCOL_FORM.withPrefix(getProtocolName()));
+ }
+
+ @Override
+ protected void init() {
+ form = getConfig().getString(Keys.PROTOCOL_FORM.withPrefix(getProtocolName()));
}
public void setForm(String form) {
diff --git a/src/main/java/org/traccar/protocol/Xrb28Protocol.java b/src/main/java/org/traccar/protocol/Xrb28Protocol.java
index 5d8af418b..135fb0928 100644
--- a/src/main/java/org/traccar/protocol/Xrb28Protocol.java
+++ b/src/main/java/org/traccar/protocol/Xrb28Protocol.java
@@ -21,22 +21,26 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
import org.traccar.model.Command;
import java.nio.charset.StandardCharsets;
+import jakarta.inject.Inject;
+
public class Xrb28Protocol extends BaseProtocol {
- public Xrb28Protocol() {
+ @Inject
+ public Xrb28Protocol(Config config) {
setSupportedDataCommands(
Command.TYPE_CUSTOM,
Command.TYPE_POSITION_SINGLE,
Command.TYPE_POSITION_PERIODIC,
Command.TYPE_ALARM_ARM,
Command.TYPE_ALARM_DISARM);
- addServer(new TrackerServer(false, getName()) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder(StandardCharsets.ISO_8859_1));
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java
index 69e5b7372..88f2d07e5 100644
--- a/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Xrb28ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.DateBuilder;
diff --git a/src/main/java/org/traccar/protocol/Xt013Protocol.java b/src/main/java/org/traccar/protocol/Xt013Protocol.java
index ebb3c123f..25809463a 100644
--- a/src/main/java/org/traccar/protocol/Xt013Protocol.java
+++ b/src/main/java/org/traccar/protocol/Xt013Protocol.java
@@ -15,20 +15,23 @@
*/
package org.traccar.protocol;
+import io.netty.handler.codec.LineBasedFrameDecoder;
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
-import io.netty.handler.codec.LineBasedFrameDecoder;
-import io.netty.handler.codec.string.StringDecoder;
-import io.netty.handler.codec.string.StringEncoder;
+import jakarta.inject.Inject;
public class Xt013Protocol extends BaseProtocol {
- public Xt013Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Xt013Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
diff --git a/src/main/java/org/traccar/protocol/Xt013ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xt013ProtocolDecoder.java
index f49fb9563..ab0b2cdaa 100644
--- a/src/main/java/org/traccar/protocol/Xt013ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Xt013ProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
diff --git a/src/main/java/org/traccar/protocol/Xt2400Protocol.java b/src/main/java/org/traccar/protocol/Xt2400Protocol.java
index 9427876c8..1b7fc840b 100644
--- a/src/main/java/org/traccar/protocol/Xt2400Protocol.java
+++ b/src/main/java/org/traccar/protocol/Xt2400Protocol.java
@@ -18,13 +18,17 @@ package org.traccar.protocol;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class Xt2400Protocol extends BaseProtocol {
- public Xt2400Protocol() {
- addServer(new TrackerServer(true, getName()) {
+ @Inject
+ public Xt2400Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), true) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new Xt2400ProtocolDecoder(Xt2400Protocol.this));
}
});
diff --git a/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java
index 85e8e140f..edcb3f535 100644
--- a/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Xt2400ProtocolDecoder.java
@@ -18,8 +18,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.Context;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
import org.traccar.config.Keys;
import org.traccar.helper.DataConverter;
@@ -38,8 +37,11 @@ public class Xt2400ProtocolDecoder extends BaseProtocolDecoder {
public Xt2400ProtocolDecoder(Protocol protocol) {
super(protocol);
+ }
- String config = Context.getConfig().getString(Keys.PROTOCOL_CONFIG.withPrefix(getProtocolName()));
+ @Override
+ protected void init() {
+ String config = getConfig().getString(Keys.PROTOCOL_CONFIG.withPrefix(getProtocolName()));
if (config != null) {
setConfig(config);
}
diff --git a/src/main/java/org/traccar/protocol/YwtProtocol.java b/src/main/java/org/traccar/protocol/YwtProtocol.java
index c525b75cf..27c71cfa8 100644
--- a/src/main/java/org/traccar/protocol/YwtProtocol.java
+++ b/src/main/java/org/traccar/protocol/YwtProtocol.java
@@ -21,13 +21,17 @@ import io.netty.handler.codec.string.StringEncoder;
import org.traccar.BaseProtocol;
import org.traccar.PipelineBuilder;
import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import jakarta.inject.Inject;
public class YwtProtocol extends BaseProtocol {
- public YwtProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public YwtProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
@Override
- protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
diff --git a/src/main/java/org/traccar/protocol/YwtProtocolDecoder.java b/src/main/java/org/traccar/protocol/YwtProtocolDecoder.java
index bf5a23fa7..fd050bee9 100644
--- a/src/main/java/org/traccar/protocol/YwtProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/YwtProtocolDecoder.java
@@ -17,7 +17,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
-import org.traccar.DeviceSession;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
diff --git a/src/main/java/org/traccar/reports/CombinedReportProvider.java b/src/main/java/org/traccar/reports/CombinedReportProvider.java
new file mode 100644
index 000000000..bad3a61b3
--- /dev/null
+++ b/src/main/java/org/traccar/reports/CombinedReportProvider.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.reports;
+
+import org.traccar.helper.model.DeviceUtil;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+import org.traccar.reports.common.ReportUtils;
+import org.traccar.reports.model.CombinedReportItem;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Order;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class CombinedReportProvider {
+
+ private static final Set<String> EXCLUDE_TYPES = Set.of(Event.TYPE_DEVICE_MOVING);
+
+ private final ReportUtils reportUtils;
+ private final Storage storage;
+
+ @Inject
+ public CombinedReportProvider(ReportUtils reportUtils, Storage storage) {
+ this.reportUtils = reportUtils;
+ this.storage = storage;
+ }
+
+ public Collection<CombinedReportItem> getObjects(
+ long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws StorageException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<CombinedReportItem> result = new ArrayList<>();
+ for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) {
+ CombinedReportItem item = new CombinedReportItem();
+ item.setDeviceId(device.getId());
+ var positions = PositionUtil.getPositions(storage, device.getId(), from, to);
+ item.setRoute(positions.stream()
+ .map(p -> new double[] {p.getLongitude(), p.getLatitude()})
+ .collect(Collectors.toList()));
+ var events = storage.getObjects(Event.class, new Request(
+ new Columns.All(),
+ new Condition.And(
+ new Condition.Equals("deviceId", device.getId()),
+ new Condition.Between("eventTime", "from", from, "to", to)),
+ new Order("eventTime")));
+ item.setEvents(events.stream()
+ .filter(e -> e.getPositionId() > 0 && !EXCLUDE_TYPES.contains(e.getType()))
+ .collect(Collectors.toList()));
+ var eventPositions = events.stream()
+ .map(Event::getPositionId)
+ .collect(Collectors.toSet());
+ item.setPositions(positions.stream()
+ .filter(p -> eventPositions.contains(p.getId()))
+ .collect(Collectors.toList()));
+ result.add(item);
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/org/traccar/reports/CsvExportProvider.java b/src/main/java/org/traccar/reports/CsvExportProvider.java
new file mode 100644
index 000000000..521dc120a
--- /dev/null
+++ b/src/main/java/org/traccar/reports/CsvExportProvider.java
@@ -0,0 +1,76 @@
+/*
+ * 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.reports;
+
+import org.traccar.helper.DateUtil;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Position;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+
+import jakarta.inject.Inject;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class CsvExportProvider {
+
+ private final Storage storage;
+
+ @Inject
+ public CsvExportProvider(Storage storage) {
+ this.storage = storage;
+ }
+
+ public void generate(
+ OutputStream outputStream, long deviceId, Date from, Date to) throws StorageException {
+
+ var positions = PositionUtil.getPositions(storage, deviceId, from, to);
+
+ var attributes = positions.stream()
+ .flatMap((position -> position.getAttributes().keySet().stream()))
+ .collect(Collectors.toUnmodifiableSet());
+
+ var properties = new LinkedHashMap<String, Function<Position, Object>>();
+ properties.put("id", Position::getId);
+ properties.put("deviceId", Position::getDeviceId);
+ properties.put("protocol", Position::getProtocol);
+ properties.put("serverTime", position -> DateUtil.formatDate(position.getServerTime()));
+ properties.put("deviceTime", position -> DateUtil.formatDate(position.getDeviceTime()));
+ properties.put("fixTime", position -> DateUtil.formatDate(position.getFixTime()));
+ properties.put("valid", Position::getValid);
+ properties.put("latitude", Position::getLatitude);
+ properties.put("longitude", Position::getLongitude);
+ properties.put("altitude", Position::getAltitude);
+ properties.put("speed", Position::getSpeed);
+ properties.put("course", Position::getCourse);
+ properties.put("address", Position::getAddress);
+ properties.put("accuracy", Position::getAccuracy);
+ attributes.forEach(key -> properties.put(key, position -> position.getAttributes().get(key)));
+
+ try (PrintWriter writer = new PrintWriter(outputStream)) {
+ writer.println(String.join(",", properties.keySet()));
+ positions.forEach(position -> writer.println(properties.values().stream()
+ .map(f -> Objects.toString(f.apply(position), ""))
+ .collect(Collectors.joining(","))));
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/Events.java b/src/main/java/org/traccar/reports/Events.java
deleted file mode 100644
index e4b905702..000000000
--- a/src/main/java/org/traccar/reports/Events.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@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.reports;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-
-import org.apache.poi.ss.util.WorkbookUtil;
-import org.traccar.Context;
-import org.traccar.model.Device;
-import org.traccar.model.Event;
-import org.traccar.model.Geofence;
-import org.traccar.model.Group;
-import org.traccar.model.Maintenance;
-import org.traccar.reports.model.DeviceReport;
-import org.traccar.storage.StorageException;
-
-public final class Events {
-
- private Events() {
- }
-
- public static Collection<Event> getObjects(long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Collection<String> types, Date from, Date to) throws StorageException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<Event> result = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- Collection<Event> events = Context.getDataManager().getEvents(deviceId, from, to);
- boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS);
- for (Event event : events) {
- if (all || types.contains(event.getType())) {
- long geofenceId = event.getGeofenceId();
- long maintenanceId = event.getMaintenanceId();
- if ((geofenceId == 0 || Context.getGeofenceManager().checkItemPermission(userId, geofenceId))
- && (maintenanceId == 0
- || Context.getMaintenancesManager().checkItemPermission(userId, maintenanceId))) {
- result.add(event);
- }
- }
- }
- }
- return result;
- }
-
- public static void getExcel(OutputStream outputStream,
- long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Collection<String> types, Date from, Date to) throws StorageException, IOException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<DeviceReport> devicesEvents = new ArrayList<>();
- ArrayList<String> sheetNames = new ArrayList<>();
- HashMap<Long, String> geofenceNames = new HashMap<>();
- HashMap<Long, String> maintenanceNames = new HashMap<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- Collection<Event> events = Context.getDataManager().getEvents(deviceId, from, to);
- boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS);
- for (Iterator<Event> iterator = events.iterator(); iterator.hasNext();) {
- Event event = iterator.next();
- if (all || types.contains(event.getType())) {
- long geofenceId = event.getGeofenceId();
- long maintenanceId = event.getMaintenanceId();
- if (geofenceId != 0) {
- if (Context.getGeofenceManager().checkItemPermission(userId, geofenceId)) {
- Geofence geofence = Context.getGeofenceManager().getById(geofenceId);
- if (geofence != null) {
- geofenceNames.put(geofenceId, geofence.getName());
- }
- } else {
- iterator.remove();
- }
- } else if (maintenanceId != 0) {
- if (Context.getMaintenancesManager().checkItemPermission(userId, maintenanceId)) {
- Maintenance maintenance = Context.getMaintenancesManager().getById(maintenanceId);
- if (maintenance != null) {
- maintenanceNames.put(maintenanceId, maintenance.getName());
- }
- } else {
- iterator.remove();
- }
- }
- } else {
- iterator.remove();
- }
- }
- DeviceReport deviceEvents = new DeviceReport();
- Device device = Context.getIdentityManager().getById(deviceId);
- deviceEvents.setDeviceName(device.getName());
- sheetNames.add(WorkbookUtil.createSafeSheetName(deviceEvents.getDeviceName()));
- if (device.getGroupId() != 0) {
- Group group = Context.getGroupsManager().getById(device.getGroupId());
- if (group != null) {
- deviceEvents.setGroupName(group.getName());
- }
- }
- deviceEvents.setObjects(events);
- devicesEvents.add(deviceEvents);
- }
- String templatePath = Context.getConfig().getString("report.templatesPath",
- "templates/export/");
- try (InputStream inputStream = new FileInputStream(templatePath + "/events.xlsx")) {
- org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId);
- jxlsContext.putVar("devices", devicesEvents);
- jxlsContext.putVar("sheetNames", sheetNames);
- jxlsContext.putVar("geofenceNames", geofenceNames);
- jxlsContext.putVar("maintenanceNames", maintenanceNames);
- jxlsContext.putVar("from", from);
- jxlsContext.putVar("to", to);
- ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext);
- }
- }
-}
diff --git a/src/main/java/org/traccar/reports/EventsReportProvider.java b/src/main/java/org/traccar/reports/EventsReportProvider.java
new file mode 100644
index 000000000..f252f28cc
--- /dev/null
+++ b/src/main/java/org/traccar/reports/EventsReportProvider.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2018 Andrey Kunitsyn (andrey@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.reports;
+
+import org.apache.poi.ss.util.WorkbookUtil;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.DeviceUtil;
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+import org.traccar.model.Geofence;
+import org.traccar.model.Group;
+import org.traccar.model.Maintenance;
+import org.traccar.model.Position;
+import org.traccar.reports.common.ReportUtils;
+import org.traccar.reports.model.DeviceReportSection;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Order;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+public class EventsReportProvider {
+
+ private final Config config;
+ private final ReportUtils reportUtils;
+ private final Storage storage;
+
+ @Inject
+ public EventsReportProvider(Config config, ReportUtils reportUtils, Storage storage) {
+ this.config = config;
+ this.reportUtils = reportUtils;
+ this.storage = storage;
+ }
+
+ private List<Event> getEvents(long deviceId, Date from, Date to) throws StorageException {
+ return storage.getObjects(Event.class, new Request(
+ new Columns.All(),
+ new Condition.And(
+ new Condition.Equals("deviceId", deviceId),
+ new Condition.Between("eventTime", "from", from, "to", to)),
+ new Order("eventTime")));
+ }
+
+ public Collection<Event> getObjects(
+ long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Collection<String> types, Date from, Date to) throws StorageException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<Event> result = new ArrayList<>();
+ for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) {
+ Collection<Event> events = getEvents(device.getId(), from, to);
+ boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS);
+ for (Event event : events) {
+ if (all || types.contains(event.getType())) {
+ long geofenceId = event.getGeofenceId();
+ long maintenanceId = event.getMaintenanceId();
+ if ((geofenceId == 0 || reportUtils.getObject(userId, Geofence.class, geofenceId) != null)
+ && (maintenanceId == 0
+ || reportUtils.getObject(userId, Maintenance.class, maintenanceId) != null)) {
+ result.add(event);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ public void getExcel(
+ OutputStream outputStream, long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Collection<String> types, Date from, Date to) throws StorageException, IOException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<DeviceReportSection> devicesEvents = new ArrayList<>();
+ ArrayList<String> sheetNames = new ArrayList<>();
+ HashMap<Long, String> geofenceNames = new HashMap<>();
+ HashMap<Long, String> maintenanceNames = new HashMap<>();
+ HashMap<Long, Position> positions = new HashMap<>();
+ for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) {
+ Collection<Event> events = getEvents(device.getId(), from, to);
+ boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS);
+ for (Iterator<Event> iterator = events.iterator(); iterator.hasNext();) {
+ Event event = iterator.next();
+ if (all || types.contains(event.getType())) {
+ long geofenceId = event.getGeofenceId();
+ long maintenanceId = event.getMaintenanceId();
+ if (geofenceId != 0) {
+ Geofence geofence = reportUtils.getObject(userId, Geofence.class, geofenceId);
+ if (geofence != null) {
+ geofenceNames.put(geofenceId, geofence.getName());
+ } else {
+ iterator.remove();
+ }
+ } else if (maintenanceId != 0) {
+ Maintenance maintenance = reportUtils.getObject(userId, Maintenance.class, maintenanceId);
+ if (maintenance != null) {
+ maintenanceNames.put(maintenanceId, maintenance.getName());
+ } else {
+ iterator.remove();
+ }
+ }
+ } else {
+ iterator.remove();
+ }
+ }
+ for (Event event : events) {
+ long positionId = event.getPositionId();
+ if (positionId > 0) {
+ Position position = storage.getObject(Position.class, new Request(
+ new Columns.All(), new Condition.Equals("id", positionId)));
+ positions.put(positionId, position);
+ }
+ }
+ DeviceReportSection deviceEvents = new DeviceReportSection();
+ deviceEvents.setDeviceName(device.getName());
+ sheetNames.add(WorkbookUtil.createSafeSheetName(deviceEvents.getDeviceName()));
+ if (device.getGroupId() > 0) {
+ Group group = storage.getObject(Group.class, new Request(
+ new Columns.All(), new Condition.Equals("id", device.getGroupId())));
+ if (group != null) {
+ deviceEvents.setGroupName(group.getName());
+ }
+ }
+ deviceEvents.setObjects(events);
+ devicesEvents.add(deviceEvents);
+ }
+
+ File file = Paths.get(config.getString(Keys.TEMPLATES_ROOT), "export", "events.xlsx").toFile();
+ try (InputStream inputStream = new FileInputStream(file)) {
+ var context = reportUtils.initializeContext(userId);
+ context.putVar("devices", devicesEvents);
+ context.putVar("sheetNames", sheetNames);
+ context.putVar("geofenceNames", geofenceNames);
+ context.putVar("maintenanceNames", maintenanceNames);
+ context.putVar("positions", positions);
+ context.putVar("from", from);
+ context.putVar("to", to);
+ reportUtils.processTemplateWithSheets(inputStream, outputStream, context);
+ }
+ }
+}
diff --git a/src/main/java/org/traccar/reports/GpxExportProvider.java b/src/main/java/org/traccar/reports/GpxExportProvider.java
new file mode 100644
index 000000000..1c45b6416
--- /dev/null
+++ b/src/main/java/org/traccar/reports/GpxExportProvider.java
@@ -0,0 +1,76 @@
+/*
+ * 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.reports;
+
+import org.traccar.helper.DateUtil;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Device;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.Date;
+
+public class GpxExportProvider {
+
+ private final Storage storage;
+
+ @Inject
+ public GpxExportProvider(Storage storage) {
+ this.storage = storage;
+ }
+
+ public void generate(
+ OutputStream outputStream, long deviceId, Date from, Date to) throws StorageException {
+
+ var device = storage.getObject(Device.class, new Request(
+ new Columns.All(), new Condition.Equals("id", deviceId)));
+ var positions = PositionUtil.getPositions(storage, deviceId, from, to);
+
+ try (PrintWriter writer = new PrintWriter(outputStream)) {
+ writer.print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ writer.print("<gpx version=\"1.0\">");
+ writer.print("<trk>");
+ writer.print("<name>");
+ writer.print(device.getName());
+ writer.print("</name>");
+ writer.print("<trkseg>");
+ positions.forEach(position -> {
+ writer.print("<trkpt lat=\"");
+ writer.print(position.getLatitude());
+ writer.print("\" lon=\"");
+ writer.print(position.getLongitude());
+ writer.print("\">");
+ writer.print("<ele>");
+ writer.print(position.getAltitude());
+ writer.print("</ele>");
+ writer.print("<time>");
+ writer.print(DateUtil.formatDate(position.getFixTime()));
+ writer.print("</time>");
+ writer.print("</trkpt>");
+ });
+ writer.print("</trkseg>");
+ writer.print("</trk>");
+ writer.print("</gpx>");
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/KmlExportProvider.java b/src/main/java/org/traccar/reports/KmlExportProvider.java
new file mode 100644
index 000000000..24dca018c
--- /dev/null
+++ b/src/main/java/org/traccar/reports/KmlExportProvider.java
@@ -0,0 +1,80 @@
+/*
+ * 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.reports;
+
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Device;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.stream.Collectors;
+
+public class KmlExportProvider {
+
+ private final Storage storage;
+
+ @Inject
+ public KmlExportProvider(Storage storage) {
+ this.storage = storage;
+ }
+
+ public void generate(
+ OutputStream outputStream, long deviceId, Date from, Date to) throws StorageException {
+
+ var device = storage.getObject(Device.class, new Request(
+ new Columns.All(), new Condition.Equals("id", deviceId)));
+ var positions = PositionUtil.getPositions(storage, deviceId, from, to);
+
+ var dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+
+ try (PrintWriter writer = new PrintWriter(outputStream)) {
+ writer.print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ writer.print("<kml xmlns=\"http://www.opengis.net/kml/2.2\">");
+ writer.print("<Document>");
+ writer.print("<name>");
+ writer.print(device.getName());
+ writer.print("</name>");
+ writer.print("<Placemark>");
+ writer.print("<name>");
+ writer.print(dateFormat.format(from));
+ writer.print(" - ");
+ writer.print(dateFormat.format(to));
+ writer.print("</name>");
+ writer.print("<LineString>");
+ writer.print("<extrude>1</extrude>");
+ writer.print("<tessellate>1</tessellate>");
+ writer.print("<altitudeMode>absolute</altitudeMode>");
+ writer.print("<coordinates>");
+ writer.print(positions.stream()
+ .map((p -> String.format("%f,%f,%f", p.getLongitude(), p.getLatitude(), p.getAltitude())))
+ .collect(Collectors.joining(" ")));
+ writer.print("</coordinates>");
+ writer.print("</LineString>");
+ writer.print("</Placemark>");
+ writer.print("</Document>");
+ writer.print("</kml>");
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/ReportUtils.java b/src/main/java/org/traccar/reports/ReportUtils.java
deleted file mode 100644
index 58674beae..000000000
--- a/src/main/java/org/traccar/reports/ReportUtils.java
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Copyright 2016 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@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.reports;
-
-import org.apache.velocity.tools.generic.DateTool;
-import org.apache.velocity.tools.generic.NumberTool;
-import org.jxls.area.Area;
-import org.jxls.builder.xls.XlsCommentAreaBuilder;
-import org.jxls.common.CellRef;
-import org.jxls.formula.StandardFormulaProcessor;
-import org.jxls.transform.Transformer;
-import org.jxls.transform.poi.PoiTransformer;
-import org.jxls.util.TransformerFactory;
-import org.traccar.Context;
-import org.traccar.config.Keys;
-import org.traccar.database.DeviceManager;
-import org.traccar.database.IdentityManager;
-import org.traccar.handler.events.MotionEventHandler;
-import org.traccar.helper.UnitsConverter;
-import org.traccar.model.DeviceState;
-import org.traccar.model.Driver;
-import org.traccar.model.Event;
-import org.traccar.model.Position;
-import org.traccar.reports.model.BaseReport;
-import org.traccar.reports.model.StopReport;
-import org.traccar.reports.model.TripReport;
-import org.traccar.reports.model.TripsConfig;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-
-public final class ReportUtils {
-
- private ReportUtils() {
- }
-
- public static void checkPeriodLimit(Date from, Date to) {
- long limit = Context.getConfig().getLong(Keys.REPORT_PERIOD_LIMIT) * 1000;
- if (limit > 0 && to.getTime() - from.getTime() > limit) {
- throw new IllegalArgumentException("Time period exceeds the limit");
- }
- }
-
- public static String getDistanceUnit(long userId) {
- return (String) Context.getPermissionsManager().lookupAttribute(userId, "distanceUnit", "km");
- }
-
- public static String getSpeedUnit(long userId) {
- return (String) Context.getPermissionsManager().lookupAttribute(userId, "speedUnit", "kn");
- }
-
- public static String getVolumeUnit(long userId) {
- return (String) Context.getPermissionsManager().lookupAttribute(userId, "volumeUnit", "ltr");
- }
-
- public static TimeZone getTimezone(long userId) {
- String timezone = (String) Context.getPermissionsManager().lookupAttribute(userId, "timezone", null);
- return timezone != null ? TimeZone.getTimeZone(timezone) : TimeZone.getDefault();
- }
-
- public static Collection<Long> getDeviceList(Collection<Long> deviceIds, Collection<Long> groupIds) {
- Collection<Long> result = new ArrayList<>(deviceIds);
- for (long groupId : groupIds) {
- result.addAll(Context.getPermissionsManager().getGroupDevices(groupId));
- }
- return result;
- }
-
- public static double calculateDistance(Position firstPosition, Position lastPosition) {
- return calculateDistance(firstPosition, lastPosition, true);
- }
-
- public static double calculateDistance(Position firstPosition, Position lastPosition, boolean useOdometer) {
- double distance = 0.0;
- double firstOdometer = firstPosition.getDouble(Position.KEY_ODOMETER);
- double lastOdometer = lastPosition.getDouble(Position.KEY_ODOMETER);
-
- if (useOdometer && firstOdometer != 0.0 && lastOdometer != 0.0) {
- distance = lastOdometer - firstOdometer;
- } else if (firstPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE)
- && lastPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE)) {
- distance = lastPosition.getDouble(Position.KEY_TOTAL_DISTANCE)
- - firstPosition.getDouble(Position.KEY_TOTAL_DISTANCE);
- }
- return distance;
- }
-
- public static double calculateFuel(Position firstPosition, Position lastPosition) {
-
- if (firstPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null
- && lastPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null) {
-
- BigDecimal value = BigDecimal.valueOf(firstPosition.getDouble(Position.KEY_FUEL_LEVEL)
- - lastPosition.getDouble(Position.KEY_FUEL_LEVEL));
- return value.setScale(1, RoundingMode.HALF_EVEN).doubleValue();
- }
- return 0;
- }
-
- public static String findDriver(Position firstPosition, Position lastPosition) {
- if (firstPosition.getAttributes().containsKey(Position.KEY_DRIVER_UNIQUE_ID)) {
- return firstPosition.getString(Position.KEY_DRIVER_UNIQUE_ID);
- } else if (lastPosition.getAttributes().containsKey(Position.KEY_DRIVER_UNIQUE_ID)) {
- return lastPosition.getString(Position.KEY_DRIVER_UNIQUE_ID);
- }
- return null;
- }
-
- public static String findDriverName(String driverUniqueId) {
- if (driverUniqueId != null && Context.getDriversManager() != null) {
- Driver driver = Context.getDriversManager().getDriverByUniqueId(driverUniqueId);
- if (driver != null) {
- return driver.getName();
- }
- }
- return null;
- }
-
- public static org.jxls.common.Context initializeContext(long userId) {
- org.jxls.common.Context jxlsContext = PoiTransformer.createInitialContext();
- jxlsContext.putVar("distanceUnit", getDistanceUnit(userId));
- jxlsContext.putVar("speedUnit", getSpeedUnit(userId));
- jxlsContext.putVar("volumeUnit", getVolumeUnit(userId));
- jxlsContext.putVar("webUrl", Context.getVelocityEngine().getProperty("web.url"));
- jxlsContext.putVar("dateTool", new DateTool());
- jxlsContext.putVar("numberTool", new NumberTool());
- jxlsContext.putVar("timezone", getTimezone(userId));
- jxlsContext.putVar("locale", Locale.getDefault());
- jxlsContext.putVar("bracketsRegex", "[\\{\\}\"]");
- return jxlsContext;
- }
-
- public static void processTemplateWithSheets(
- InputStream templateStream, OutputStream targetStream,
- org.jxls.common.Context jxlsContext) throws IOException {
-
- Transformer transformer = TransformerFactory.createTransformer(templateStream, targetStream);
- List<Area> xlsAreas = new XlsCommentAreaBuilder(transformer).build();
- for (Area xlsArea : xlsAreas) {
- xlsArea.applyAt(new CellRef(xlsArea.getStartCellRef().getCellName()), jxlsContext);
- xlsArea.setFormulaProcessor(new StandardFormulaProcessor());
- xlsArea.processFormulas();
- }
- transformer.deleteSheet(xlsAreas.get(0).getStartCellRef().getSheetName());
- transformer.write();
- }
-
- private static TripReport calculateTrip(
- ArrayList<Position> positions, int startIndex, int endIndex, boolean ignoreOdometer) {
-
- Position startTrip = positions.get(startIndex);
- Position endTrip = positions.get(endIndex);
-
- double speedMax = 0;
- for (int i = startIndex; i <= endIndex; i++) {
- double speed = positions.get(i).getSpeed();
- if (speed > speedMax) {
- speedMax = speed;
- }
- }
-
- TripReport trip = new TripReport();
-
- long tripDuration = endTrip.getFixTime().getTime() - startTrip.getFixTime().getTime();
- long deviceId = startTrip.getDeviceId();
- trip.setDeviceId(deviceId);
- trip.setDeviceName(Context.getIdentityManager().getById(deviceId).getName());
-
- trip.setStartPositionId(startTrip.getId());
- trip.setStartLat(startTrip.getLatitude());
- trip.setStartLon(startTrip.getLongitude());
- trip.setStartTime(startTrip.getFixTime());
- String startAddress = startTrip.getAddress();
- if (startAddress == null && Context.getGeocoder() != null
- && Context.getConfig().getBoolean(Keys.GEOCODER_ON_REQUEST)) {
- startAddress = Context.getGeocoder().getAddress(startTrip.getLatitude(), startTrip.getLongitude(), null);
- }
- trip.setStartAddress(startAddress);
-
- trip.setEndPositionId(endTrip.getId());
- trip.setEndLat(endTrip.getLatitude());
- trip.setEndLon(endTrip.getLongitude());
- trip.setEndTime(endTrip.getFixTime());
- String endAddress = endTrip.getAddress();
- if (endAddress == null && Context.getGeocoder() != null
- && Context.getConfig().getBoolean(Keys.GEOCODER_ON_REQUEST)) {
- endAddress = Context.getGeocoder().getAddress(endTrip.getLatitude(), endTrip.getLongitude(), null);
- }
- trip.setEndAddress(endAddress);
-
- trip.setDistance(calculateDistance(startTrip, endTrip, !ignoreOdometer));
- trip.setDuration(tripDuration);
- if (tripDuration > 0) {
- trip.setAverageSpeed(UnitsConverter.knotsFromMps(trip.getDistance() * 1000 / tripDuration));
- }
- trip.setMaxSpeed(speedMax);
- trip.setSpentFuel(calculateFuel(startTrip, endTrip));
-
- trip.setDriverUniqueId(findDriver(startTrip, endTrip));
- trip.setDriverName(findDriverName(trip.getDriverUniqueId()));
-
- if (!ignoreOdometer
- && startTrip.getDouble(Position.KEY_ODOMETER) != 0
- && endTrip.getDouble(Position.KEY_ODOMETER) != 0) {
- trip.setStartOdometer(startTrip.getDouble(Position.KEY_ODOMETER));
- trip.setEndOdometer(endTrip.getDouble(Position.KEY_ODOMETER));
- } else {
- trip.setStartOdometer(startTrip.getDouble(Position.KEY_TOTAL_DISTANCE));
- trip.setEndOdometer(endTrip.getDouble(Position.KEY_TOTAL_DISTANCE));
- }
-
- return trip;
- }
-
- private static StopReport calculateStop(
- ArrayList<Position> positions, int startIndex, int endIndex, boolean ignoreOdometer) {
-
- Position startStop = positions.get(startIndex);
- Position endStop = positions.get(endIndex);
-
- StopReport stop = new StopReport();
-
- long deviceId = startStop.getDeviceId();
- stop.setDeviceId(deviceId);
- stop.setDeviceName(Context.getIdentityManager().getById(deviceId).getName());
-
- stop.setPositionId(startStop.getId());
- stop.setLatitude(startStop.getLatitude());
- stop.setLongitude(startStop.getLongitude());
- stop.setStartTime(startStop.getFixTime());
- String address = startStop.getAddress();
- if (address == null && Context.getGeocoder() != null
- && Context.getConfig().getBoolean(Keys.GEOCODER_ON_REQUEST)) {
- address = Context.getGeocoder().getAddress(stop.getLatitude(), stop.getLongitude(), null);
- }
- stop.setAddress(address);
-
- stop.setEndTime(endStop.getFixTime());
-
- long stopDuration = endStop.getFixTime().getTime() - startStop.getFixTime().getTime();
- stop.setDuration(stopDuration);
- stop.setSpentFuel(calculateFuel(startStop, endStop));
-
- if (startStop.getAttributes().containsKey(Position.KEY_HOURS)
- && endStop.getAttributes().containsKey(Position.KEY_HOURS)) {
- stop.setEngineHours(endStop.getLong(Position.KEY_HOURS) - startStop.getLong(Position.KEY_HOURS));
- }
-
- if (!ignoreOdometer
- && startStop.getDouble(Position.KEY_ODOMETER) != 0
- && endStop.getDouble(Position.KEY_ODOMETER) != 0) {
- stop.setStartOdometer(startStop.getDouble(Position.KEY_ODOMETER));
- stop.setEndOdometer(endStop.getDouble(Position.KEY_ODOMETER));
- } else {
- stop.setStartOdometer(startStop.getDouble(Position.KEY_TOTAL_DISTANCE));
- stop.setEndOdometer(endStop.getDouble(Position.KEY_TOTAL_DISTANCE));
- }
-
- return stop;
-
- }
-
- private static <T extends BaseReport> T calculateTripOrStop(
- ArrayList<Position> positions, int startIndex, int endIndex, boolean ignoreOdometer, Class<T> reportClass) {
-
- if (reportClass.equals(TripReport.class)) {
- return (T) calculateTrip(positions, startIndex, endIndex, ignoreOdometer);
- } else {
- return (T) calculateStop(positions, startIndex, endIndex, ignoreOdometer);
- }
- }
-
- private static boolean isMoving(ArrayList<Position> positions, int index, TripsConfig tripsConfig) {
- if (tripsConfig.getMinimalNoDataDuration() > 0) {
- boolean beforeGap = index < positions.size() - 1
- && positions.get(index + 1).getFixTime().getTime() - positions.get(index).getFixTime().getTime()
- >= tripsConfig.getMinimalNoDataDuration();
- boolean afterGap = index > 0
- && positions.get(index).getFixTime().getTime() - positions.get(index - 1).getFixTime().getTime()
- >= tripsConfig.getMinimalNoDataDuration();
- if (beforeGap || afterGap) {
- return false;
- }
- }
- if (positions.get(index).getAttributes().containsKey(Position.KEY_MOTION)
- && positions.get(index).getAttributes().get(Position.KEY_MOTION) instanceof Boolean) {
- return positions.get(index).getBoolean(Position.KEY_MOTION);
- } else {
- return positions.get(index).getSpeed() > tripsConfig.getSpeedThreshold();
- }
- }
-
- public static <T extends BaseReport> Collection<T> detectTripsAndStops(
- IdentityManager identityManager, DeviceManager deviceManager,
- Collection<Position> positionCollection,
- TripsConfig tripsConfig, boolean ignoreOdometer, Class<T> reportClass) {
-
- Collection<T> result = new ArrayList<>();
-
- ArrayList<Position> positions = new ArrayList<>(positionCollection);
- if (!positions.isEmpty()) {
- boolean trips = reportClass.equals(TripReport.class);
- MotionEventHandler motionHandler = new MotionEventHandler(identityManager, deviceManager, tripsConfig);
- DeviceState deviceState = new DeviceState();
- deviceState.setMotionState(isMoving(positions, 0, tripsConfig));
- int startEventIndex = trips == deviceState.getMotionState() ? 0 : -1;
- int startNoEventIndex = -1;
- for (int i = 0; i < positions.size(); i++) {
- Map<Event, Position> event = motionHandler.updateMotionState(deviceState, positions.get(i),
- isMoving(positions, i, tripsConfig));
- if (startEventIndex == -1
- && (trips != deviceState.getMotionState() && deviceState.getMotionPosition() != null
- || trips == deviceState.getMotionState() && event != null)) {
- startEventIndex = i;
- startNoEventIndex = -1;
- } else if (trips != deviceState.getMotionState() && startEventIndex != -1
- && deviceState.getMotionPosition() == null && event == null) {
- startEventIndex = -1;
- }
- if (startNoEventIndex == -1
- && (trips == deviceState.getMotionState() && deviceState.getMotionPosition() != null
- || trips != deviceState.getMotionState() && event != null)) {
- startNoEventIndex = i;
- } else if (startNoEventIndex != -1 && deviceState.getMotionPosition() == null && event == null) {
- startNoEventIndex = -1;
- }
- if (startEventIndex != -1 && startNoEventIndex != -1 && event != null
- && trips != deviceState.getMotionState()) {
- result.add(calculateTripOrStop(positions, startEventIndex, startNoEventIndex,
- ignoreOdometer, reportClass));
- startEventIndex = -1;
- }
- }
- if (startEventIndex != -1 && (startNoEventIndex != -1 || !trips)) {
- result.add(calculateTripOrStop(positions, startEventIndex,
- startNoEventIndex != -1 ? startNoEventIndex : positions.size() - 1,
- ignoreOdometer, reportClass));
- }
- }
-
- return result;
- }
-
-}
diff --git a/src/main/java/org/traccar/reports/Route.java b/src/main/java/org/traccar/reports/Route.java
deleted file mode 100644
index 4a5edd295..000000000
--- a/src/main/java/org/traccar/reports/Route.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 Andrey Kunitsyn (andrey@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.reports;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-
-import org.apache.poi.ss.util.WorkbookUtil;
-import org.traccar.Context;
-import org.traccar.model.Device;
-import org.traccar.model.Group;
-import org.traccar.model.Position;
-import org.traccar.reports.model.DeviceReport;
-import org.traccar.storage.StorageException;
-
-public final class Route {
-
- private Route() {
- }
-
- public static Collection<Position> getObjects(long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to) throws StorageException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<Position> result = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- result.addAll(Context.getDataManager().getPositions(deviceId, from, to));
- }
- return result;
- }
-
- public static void getExcel(OutputStream outputStream,
- long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to) throws StorageException, IOException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<DeviceReport> devicesRoutes = new ArrayList<>();
- ArrayList<String> sheetNames = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- Collection<Position> positions = Context.getDataManager()
- .getPositions(deviceId, from, to);
- DeviceReport deviceRoutes = new DeviceReport();
- Device device = Context.getIdentityManager().getById(deviceId);
- deviceRoutes.setDeviceName(device.getName());
- sheetNames.add(WorkbookUtil.createSafeSheetName(deviceRoutes.getDeviceName()));
- if (device.getGroupId() != 0) {
- Group group = Context.getGroupsManager().getById(device.getGroupId());
- if (group != null) {
- deviceRoutes.setGroupName(group.getName());
- }
- }
- deviceRoutes.setObjects(positions);
- devicesRoutes.add(deviceRoutes);
- }
- String templatePath = Context.getConfig().getString("report.templatesPath",
- "templates/export/");
- try (InputStream inputStream = new FileInputStream(templatePath + "/route.xlsx")) {
- org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId);
- jxlsContext.putVar("devices", devicesRoutes);
- jxlsContext.putVar("sheetNames", sheetNames);
- jxlsContext.putVar("from", from);
- jxlsContext.putVar("to", to);
- ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext);
- }
- }
-}
diff --git a/src/main/java/org/traccar/reports/RouteReportProvider.java b/src/main/java/org/traccar/reports/RouteReportProvider.java
new file mode 100644
index 000000000..d761fe1e5
--- /dev/null
+++ b/src/main/java/org/traccar/reports/RouteReportProvider.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 Andrey Kunitsyn (andrey@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.reports;
+
+import org.apache.poi.ss.util.WorkbookUtil;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.DeviceUtil;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.model.Position;
+import org.traccar.reports.common.ReportUtils;
+import org.traccar.reports.model.DeviceReportSection;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+import java.util.HashMap;
+
+public class RouteReportProvider {
+
+ private final Config config;
+ private final ReportUtils reportUtils;
+ private final Storage storage;
+
+ private final Map<String, Integer> namesCount = new HashMap<>();
+
+ @Inject
+ public RouteReportProvider(Config config, ReportUtils reportUtils, Storage storage) {
+ this.config = config;
+ this.reportUtils = reportUtils;
+ this.storage = storage;
+ }
+
+ public Collection<Position> getObjects(long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws StorageException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<Position> result = new ArrayList<>();
+ for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) {
+ result.addAll(PositionUtil.getPositions(storage, device.getId(), from, to));
+ }
+ return result;
+ }
+
+
+ private String getUniqueSheetName(String key) {
+ namesCount.compute(key, (k, value) -> value == null ? 1 : (value + 1));
+ return namesCount.get(key) > 1 ? key + '-' + namesCount.get(key) : key;
+ }
+
+ public void getExcel(OutputStream outputStream,
+ long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws StorageException, IOException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<DeviceReportSection> devicesRoutes = new ArrayList<>();
+ ArrayList<String> sheetNames = new ArrayList<>();
+ for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) {
+ var positions = PositionUtil.getPositions(storage, device.getId(), from, to);
+ DeviceReportSection deviceRoutes = new DeviceReportSection();
+ deviceRoutes.setDeviceName(device.getName());
+ sheetNames.add(WorkbookUtil.createSafeSheetName(getUniqueSheetName(deviceRoutes.getDeviceName())));
+ if (device.getGroupId() > 0) {
+ Group group = storage.getObject(Group.class, new Request(
+ new Columns.All(), new Condition.Equals("id", device.getGroupId())));
+ if (group != null) {
+ deviceRoutes.setGroupName(group.getName());
+ }
+ }
+ deviceRoutes.setObjects(positions);
+ devicesRoutes.add(deviceRoutes);
+ }
+
+ File file = Paths.get(config.getString(Keys.TEMPLATES_ROOT), "export", "route.xlsx").toFile();
+ try (InputStream inputStream = new FileInputStream(file)) {
+ var context = reportUtils.initializeContext(userId);
+ context.putVar("devices", devicesRoutes);
+ context.putVar("sheetNames", sheetNames);
+ context.putVar("from", from);
+ context.putVar("to", to);
+ reportUtils.processTemplateWithSheets(inputStream, outputStream, context);
+ }
+ }
+}
diff --git a/src/main/java/org/traccar/reports/Stops.java b/src/main/java/org/traccar/reports/Stops.java
deleted file mode 100644
index 36a4a7549..000000000
--- a/src/main/java/org/traccar/reports/Stops.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.reports;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-
-import org.apache.poi.ss.util.WorkbookUtil;
-import org.traccar.Context;
-import org.traccar.Main;
-import org.traccar.database.DeviceManager;
-import org.traccar.database.IdentityManager;
-import org.traccar.model.Device;
-import org.traccar.model.Group;
-import org.traccar.reports.model.DeviceReport;
-import org.traccar.reports.model.StopReport;
-import org.traccar.storage.StorageException;
-
-public final class Stops {
-
- private Stops() {
- }
-
- private static Collection<StopReport> detectStops(long deviceId, Date from, Date to) throws StorageException {
- boolean ignoreOdometer = Context.getDeviceManager()
- .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true);
-
- IdentityManager identityManager = Main.getInjector().getInstance(IdentityManager.class);
- DeviceManager deviceManager = Main.getInjector().getInstance(DeviceManager.class);
-
- return ReportUtils.detectTripsAndStops(
- identityManager, deviceManager, Context.getDataManager().getPositions(deviceId, from, to),
- Context.getTripsConfig(), ignoreOdometer, StopReport.class);
- }
-
- public static Collection<StopReport> getObjects(
- long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to) throws StorageException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<StopReport> result = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- result.addAll(detectStops(deviceId, from, to));
- }
- return result;
- }
-
- public static void getExcel(
- OutputStream outputStream, long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to) throws StorageException, IOException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<DeviceReport> devicesStops = new ArrayList<>();
- ArrayList<String> sheetNames = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- Collection<StopReport> stops = detectStops(deviceId, from, to);
- DeviceReport deviceStops = new DeviceReport();
- Device device = Context.getIdentityManager().getById(deviceId);
- deviceStops.setDeviceName(device.getName());
- sheetNames.add(WorkbookUtil.createSafeSheetName(deviceStops.getDeviceName()));
- if (device.getGroupId() != 0) {
- Group group = Context.getGroupsManager().getById(device.getGroupId());
- if (group != null) {
- deviceStops.setGroupName(group.getName());
- }
- }
- deviceStops.setObjects(stops);
- devicesStops.add(deviceStops);
- }
- String templatePath = Context.getConfig().getString("report.templatesPath",
- "templates/export/");
- try (InputStream inputStream = new FileInputStream(templatePath + "/stops.xlsx")) {
- org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId);
- jxlsContext.putVar("devices", devicesStops);
- jxlsContext.putVar("sheetNames", sheetNames);
- jxlsContext.putVar("from", from);
- jxlsContext.putVar("to", to);
- ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext);
- }
- }
-
-}
diff --git a/src/main/java/org/traccar/reports/StopsReportProvider.java b/src/main/java/org/traccar/reports/StopsReportProvider.java
new file mode 100644
index 000000000..2160fec0e
--- /dev/null
+++ b/src/main/java/org/traccar/reports/StopsReportProvider.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 Andrey Kunitsyn (andrey@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.reports;
+
+import org.apache.poi.ss.util.WorkbookUtil;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.DeviceUtil;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.reports.common.ReportUtils;
+import org.traccar.reports.model.DeviceReportSection;
+import org.traccar.reports.model.StopReportItem;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+public class StopsReportProvider {
+
+ private final Config config;
+ private final ReportUtils reportUtils;
+ private final Storage storage;
+
+ @Inject
+ public StopsReportProvider(Config config, ReportUtils reportUtils, Storage storage) {
+ this.config = config;
+ this.reportUtils = reportUtils;
+ this.storage = storage;
+ }
+
+ public Collection<StopReportItem> getObjects(
+ long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws StorageException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<StopReportItem> result = new ArrayList<>();
+ for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) {
+ result.addAll(reportUtils.detectTripsAndStops(device, from, to, StopReportItem.class));
+ }
+ return result;
+ }
+
+ public void getExcel(
+ OutputStream outputStream, long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws StorageException, IOException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<DeviceReportSection> devicesStops = new ArrayList<>();
+ ArrayList<String> sheetNames = new ArrayList<>();
+ for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) {
+ Collection<StopReportItem> stops = reportUtils.detectTripsAndStops(device, from, to, StopReportItem.class);
+ DeviceReportSection deviceStops = new DeviceReportSection();
+ deviceStops.setDeviceName(device.getName());
+ sheetNames.add(WorkbookUtil.createSafeSheetName(deviceStops.getDeviceName()));
+ if (device.getGroupId() > 0) {
+ Group group = storage.getObject(Group.class, new Request(
+ new Columns.All(), new Condition.Equals("id", device.getGroupId())));
+ if (group != null) {
+ deviceStops.setGroupName(group.getName());
+ }
+ }
+ deviceStops.setObjects(stops);
+ devicesStops.add(deviceStops);
+ }
+
+ File file = Paths.get(config.getString(Keys.TEMPLATES_ROOT), "export", "stops.xlsx").toFile();
+ try (InputStream inputStream = new FileInputStream(file)) {
+ var context = reportUtils.initializeContext(userId);
+ context.putVar("devices", devicesStops);
+ context.putVar("sheetNames", sheetNames);
+ context.putVar("from", from);
+ context.putVar("to", to);
+ reportUtils.processTemplateWithSheets(inputStream, outputStream, context);
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/Summary.java b/src/main/java/org/traccar/reports/Summary.java
deleted file mode 100644
index 4924af062..000000000
--- a/src/main/java/org/traccar/reports/Summary.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2016 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 Andrey Kunitsyn (andrey@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.reports;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Date;
-
-import org.jxls.util.JxlsHelper;
-import org.traccar.Context;
-import org.traccar.helper.UnitsConverter;
-import org.traccar.model.Position;
-import org.traccar.reports.model.SummaryReport;
-import org.traccar.storage.StorageException;
-
-public final class Summary {
-
- private Summary() {
- }
-
- private static SummaryReport calculateSummaryResult(long deviceId, Collection<Position> positions) {
- SummaryReport result = new SummaryReport();
- result.setDeviceId(deviceId);
- result.setDeviceName(Context.getIdentityManager().getById(deviceId).getName());
- if (positions != null && !positions.isEmpty()) {
- Position firstPosition = null;
- Position previousPosition = null;
- for (Position position : positions) {
- if (firstPosition == null) {
- firstPosition = position;
- }
- previousPosition = position;
- if (position.getSpeed() > result.getMaxSpeed()) {
- result.setMaxSpeed(position.getSpeed());
- }
- }
- boolean ignoreOdometer = Context.getDeviceManager()
- .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true);
- result.setDistance(ReportUtils.calculateDistance(firstPosition, previousPosition, !ignoreOdometer));
- result.setSpentFuel(ReportUtils.calculateFuel(firstPosition, previousPosition));
-
- long durationMilliseconds;
- if (firstPosition.getAttributes().containsKey(Position.KEY_HOURS)
- && previousPosition.getAttributes().containsKey(Position.KEY_HOURS)) {
- durationMilliseconds =
- previousPosition.getLong(Position.KEY_HOURS) - firstPosition.getLong(Position.KEY_HOURS);
- result.setEngineHours(durationMilliseconds);
- } else {
- durationMilliseconds =
- previousPosition.getFixTime().getTime() - firstPosition.getFixTime().getTime();
- }
-
- if (durationMilliseconds > 0) {
- result.setAverageSpeed(
- UnitsConverter.knotsFromMps(result.getDistance() * 1000 / durationMilliseconds));
- }
-
- if (!ignoreOdometer
- && firstPosition.getDouble(Position.KEY_ODOMETER) != 0
- && previousPosition.getDouble(Position.KEY_ODOMETER) != 0) {
- result.setStartOdometer(firstPosition.getDouble(Position.KEY_ODOMETER));
- result.setEndOdometer(previousPosition.getDouble(Position.KEY_ODOMETER));
- } else {
- result.setStartOdometer(firstPosition.getDouble(Position.KEY_TOTAL_DISTANCE));
- result.setEndOdometer(previousPosition.getDouble(Position.KEY_TOTAL_DISTANCE));
- }
-
- result.setStartTime(firstPosition.getFixTime());
- result.setEndTime(previousPosition.getFixTime());
- }
- return result;
- }
-
- private static int getDay(long userId, Date date) {
- Calendar calendar = Calendar.getInstance(ReportUtils.getTimezone(userId));
- calendar.setTime(date);
- return calendar.get(Calendar.DAY_OF_MONTH);
- }
-
- private static Collection<SummaryReport> calculateSummaryResults(
- long userId, long deviceId, Date from, Date to, boolean daily) throws StorageException {
-
- ArrayList<Position> positions = new ArrayList<>(Context.getDataManager().getPositions(deviceId, from, to));
-
- ArrayList<SummaryReport> results = new ArrayList<>();
- if (daily && !positions.isEmpty()) {
- int startIndex = 0;
- int startDay = getDay(userId, positions.iterator().next().getFixTime());
- for (int i = 0; i < positions.size(); i++) {
- int currentDay = getDay(userId, positions.get(i).getFixTime());
- if (currentDay != startDay) {
- results.add(calculateSummaryResult(deviceId, positions.subList(startIndex, i)));
- startIndex = i;
- startDay = currentDay;
- }
- }
- results.add(calculateSummaryResult(deviceId, positions.subList(startIndex, positions.size())));
- } else {
- results.add(calculateSummaryResult(deviceId, positions));
- }
-
- return results;
- }
-
- public static Collection<SummaryReport> getObjects(long userId, Collection<Long> deviceIds,
- Collection<Long> groupIds, Date from, Date to, boolean daily) throws StorageException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<SummaryReport> result = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- result.addAll(calculateSummaryResults(userId, deviceId, from, to, daily));
- }
- return result;
- }
-
- public static void getExcel(OutputStream outputStream,
- long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to, boolean daily) throws StorageException, IOException {
- ReportUtils.checkPeriodLimit(from, to);
- Collection<SummaryReport> summaries = getObjects(userId, deviceIds, groupIds, from, to, daily);
- String templatePath = Context.getConfig().getString("report.templatesPath",
- "templates/export/");
- try (InputStream inputStream = new FileInputStream(templatePath + "/summary.xlsx")) {
- org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId);
- jxlsContext.putVar("summaries", summaries);
- jxlsContext.putVar("from", from);
- jxlsContext.putVar("to", to);
- JxlsHelper.getInstance().setUseFastFormulaProcessor(false)
- .processTemplate(inputStream, outputStream, jxlsContext);
- }
- }
-}
diff --git a/src/main/java/org/traccar/reports/SummaryReportProvider.java b/src/main/java/org/traccar/reports/SummaryReportProvider.java
new file mode 100644
index 000000000..ffde0b067
--- /dev/null
+++ b/src/main/java/org/traccar/reports/SummaryReportProvider.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 Andrey Kunitsyn (andrey@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.reports;
+
+import org.jxls.util.JxlsHelper;
+import org.traccar.api.security.PermissionsService;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.helper.model.DeviceUtil;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.helper.model.UserUtil;
+import org.traccar.model.Device;
+import org.traccar.model.Position;
+import org.traccar.reports.common.ReportUtils;
+import org.traccar.reports.model.SummaryReportItem;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Order;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+public class SummaryReportProvider {
+
+ private final Config config;
+ private final ReportUtils reportUtils;
+ private final PermissionsService permissionsService;
+ private final Storage storage;
+
+ @Inject
+ public SummaryReportProvider(
+ Config config, ReportUtils reportUtils, PermissionsService permissionsService, Storage storage) {
+ this.config = config;
+ this.reportUtils = reportUtils;
+ this.permissionsService = permissionsService;
+ this.storage = storage;
+ }
+
+ private Position getEdgePosition(long deviceId, Date from, Date to, boolean end) throws StorageException {
+ return storage.getObject(Position.class, new Request(
+ new Columns.All(),
+ new Condition.And(
+ new Condition.Equals("deviceId", deviceId),
+ new Condition.Between("fixTime", "from", from, "to", to)),
+ new Order("fixTime", end, 1)));
+ }
+
+ private Collection<SummaryReportItem> calculateDeviceResult(
+ Device device, Date from, Date to, boolean fast) throws StorageException {
+
+ SummaryReportItem result = new SummaryReportItem();
+ result.setDeviceId(device.getId());
+ result.setDeviceName(device.getName());
+
+ Position first = null;
+ Position last = null;
+ if (fast) {
+ first = getEdgePosition(device.getId(), from, to, false);
+ last = getEdgePosition(device.getId(), from, to, true);
+ } else {
+ var positions = PositionUtil.getPositions(storage, device.getId(), from, to);
+ for (Position position : positions) {
+ if (first == null) {
+ first = position;
+ }
+ if (position.getSpeed() > result.getMaxSpeed()) {
+ result.setMaxSpeed(position.getSpeed());
+ }
+ last = position;
+ }
+ }
+
+ if (first != null && last != null) {
+ boolean ignoreOdometer = config.getBoolean(Keys.REPORT_IGNORE_ODOMETER);
+ result.setDistance(PositionUtil.calculateDistance(first, last, !ignoreOdometer));
+ result.setSpentFuel(reportUtils.calculateFuel(first, last));
+
+ long durationMilliseconds;
+ if (first.hasAttribute(Position.KEY_HOURS) && last.hasAttribute(Position.KEY_HOURS)) {
+ durationMilliseconds = last.getLong(Position.KEY_HOURS) - first.getLong(Position.KEY_HOURS);
+ result.setEngineHours(durationMilliseconds);
+ } else {
+ durationMilliseconds = last.getFixTime().getTime() - first.getFixTime().getTime();
+ }
+
+ if (durationMilliseconds > 0) {
+ result.setAverageSpeed(UnitsConverter.knotsFromMps(result.getDistance() * 1000 / durationMilliseconds));
+ }
+
+ if (!ignoreOdometer
+ && first.getDouble(Position.KEY_ODOMETER) != 0 && last.getDouble(Position.KEY_ODOMETER) != 0) {
+ result.setStartOdometer(first.getDouble(Position.KEY_ODOMETER));
+ result.setEndOdometer(last.getDouble(Position.KEY_ODOMETER));
+ } else {
+ result.setStartOdometer(first.getDouble(Position.KEY_TOTAL_DISTANCE));
+ result.setEndOdometer(last.getDouble(Position.KEY_TOTAL_DISTANCE));
+ }
+
+ result.setStartTime(first.getFixTime());
+ result.setEndTime(last.getFixTime());
+ return List.of(result);
+ }
+
+ return List.of();
+ }
+
+ private Collection<SummaryReportItem> calculateDeviceResults(
+ Device device, ZonedDateTime from, ZonedDateTime to, boolean daily) throws StorageException {
+
+ boolean fast = Duration.between(from, to).toSeconds() > config.getLong(Keys.REPORT_FAST_THRESHOLD);
+ var results = new ArrayList<SummaryReportItem>();
+ if (daily) {
+ while (from.truncatedTo(ChronoUnit.DAYS).isBefore(to.truncatedTo(ChronoUnit.DAYS))) {
+ ZonedDateTime fromDay = from.truncatedTo(ChronoUnit.DAYS);
+ ZonedDateTime nextDay = fromDay.plus(1, ChronoUnit.DAYS);
+ results.addAll(calculateDeviceResult(
+ device, Date.from(from.toInstant()), Date.from(nextDay.toInstant()), fast));
+ from = nextDay;
+ }
+ results.addAll(calculateDeviceResult(device, Date.from(from.toInstant()), Date.from(to.toInstant()), fast));
+ } else {
+ results.addAll(calculateDeviceResult(device, Date.from(from.toInstant()), Date.from(to.toInstant()), fast));
+ }
+ return results;
+ }
+
+ public Collection<SummaryReportItem> getObjects(
+ long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to, boolean daily) throws StorageException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ var tz = UserUtil.getTimezone(permissionsService.getServer(), permissionsService.getUser(userId)).toZoneId();
+
+ ArrayList<SummaryReportItem> result = new ArrayList<>();
+ for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) {
+ var deviceResults = calculateDeviceResults(
+ device, from.toInstant().atZone(tz), to.toInstant().atZone(tz), daily);
+ for (SummaryReportItem summaryReport : deviceResults) {
+ if (summaryReport.getStartTime() != null && summaryReport.getEndTime() != null) {
+ result.add(summaryReport);
+ }
+ }
+ }
+ return result;
+ }
+
+ public void getExcel(OutputStream outputStream,
+ long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to, boolean daily) throws StorageException, IOException {
+ Collection<SummaryReportItem> summaries = getObjects(userId, deviceIds, groupIds, from, to, daily);
+
+ File file = Paths.get(config.getString(Keys.TEMPLATES_ROOT), "export", "summary.xlsx").toFile();
+ try (InputStream inputStream = new FileInputStream(file)) {
+ var context = reportUtils.initializeContext(userId);
+ context.putVar("summaries", summaries);
+ context.putVar("from", from);
+ context.putVar("to", to);
+ JxlsHelper.getInstance().setUseFastFormulaProcessor(false)
+ .processTemplate(inputStream, outputStream, context);
+ }
+ }
+}
diff --git a/src/main/java/org/traccar/reports/Trips.java b/src/main/java/org/traccar/reports/Trips.java
deleted file mode 100644
index 1461b869e..000000000
--- a/src/main/java/org/traccar/reports/Trips.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 Andrey Kunitsyn (andrey@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.reports;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-
-import org.apache.poi.ss.util.WorkbookUtil;
-import org.traccar.Context;
-import org.traccar.Main;
-import org.traccar.database.DeviceManager;
-import org.traccar.database.IdentityManager;
-import org.traccar.model.Device;
-import org.traccar.model.Group;
-import org.traccar.reports.model.DeviceReport;
-import org.traccar.reports.model.TripReport;
-import org.traccar.storage.StorageException;
-
-public final class Trips {
-
- private Trips() {
- }
-
- private static Collection<TripReport> detectTrips(long deviceId, Date from, Date to) throws StorageException {
- boolean ignoreOdometer = Context.getDeviceManager()
- .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true);
-
- IdentityManager identityManager = Main.getInjector().getInstance(IdentityManager.class);
- DeviceManager deviceManager = Main.getInjector().getInstance(DeviceManager.class);
-
- return ReportUtils.detectTripsAndStops(
- identityManager, deviceManager, Context.getDataManager().getPositions(deviceId, from, to),
- Context.getTripsConfig(), ignoreOdometer, TripReport.class);
- }
-
- public static Collection<TripReport> getObjects(long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to) throws StorageException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<TripReport> result = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- result.addAll(detectTrips(deviceId, from, to));
- }
- return result;
- }
-
- public static void getExcel(OutputStream outputStream,
- long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to) throws StorageException, IOException {
- ReportUtils.checkPeriodLimit(from, to);
- ArrayList<DeviceReport> devicesTrips = new ArrayList<>();
- ArrayList<String> sheetNames = new ArrayList<>();
- for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) {
- Context.getPermissionsManager().checkDevice(userId, deviceId);
- Collection<TripReport> trips = detectTrips(deviceId, from, to);
- DeviceReport deviceTrips = new DeviceReport();
- Device device = Context.getIdentityManager().getById(deviceId);
- deviceTrips.setDeviceName(device.getName());
- sheetNames.add(WorkbookUtil.createSafeSheetName(deviceTrips.getDeviceName()));
- if (device.getGroupId() != 0) {
- Group group = Context.getGroupsManager().getById(device.getGroupId());
- if (group != null) {
- deviceTrips.setGroupName(group.getName());
- }
- }
- deviceTrips.setObjects(trips);
- devicesTrips.add(deviceTrips);
- }
- String templatePath = Context.getConfig().getString("report.templatesPath",
- "templates/export/");
- try (InputStream inputStream = new FileInputStream(templatePath + "/trips.xlsx")) {
- org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId);
- jxlsContext.putVar("devices", devicesTrips);
- jxlsContext.putVar("sheetNames", sheetNames);
- jxlsContext.putVar("from", from);
- jxlsContext.putVar("to", to);
- ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext);
- }
- }
-
-}
diff --git a/src/main/java/org/traccar/reports/TripsReportProvider.java b/src/main/java/org/traccar/reports/TripsReportProvider.java
new file mode 100644
index 000000000..9ff7232af
--- /dev/null
+++ b/src/main/java/org/traccar/reports/TripsReportProvider.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 Andrey Kunitsyn (andrey@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.reports;
+
+import org.apache.poi.ss.util.WorkbookUtil;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.DeviceUtil;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.reports.common.ReportUtils;
+import org.traccar.reports.model.DeviceReportSection;
+import org.traccar.reports.model.TripReportItem;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+public class TripsReportProvider {
+
+ private final Config config;
+ private final ReportUtils reportUtils;
+ private final Storage storage;
+
+ @Inject
+ public TripsReportProvider(Config config, ReportUtils reportUtils, Storage storage) {
+ this.config = config;
+ this.reportUtils = reportUtils;
+ this.storage = storage;
+ }
+
+ public Collection<TripReportItem> getObjects(
+ long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws StorageException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<TripReportItem> result = new ArrayList<>();
+ for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) {
+ result.addAll(reportUtils.detectTripsAndStops(device, from, to, TripReportItem.class));
+ }
+ return result;
+ }
+
+ public void getExcel(OutputStream outputStream,
+ long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
+ Date from, Date to) throws StorageException, IOException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<DeviceReportSection> devicesTrips = new ArrayList<>();
+ ArrayList<String> sheetNames = new ArrayList<>();
+ for (Device device: DeviceUtil.getAccessibleDevices(storage, userId, deviceIds, groupIds)) {
+ Collection<TripReportItem> trips = reportUtils.detectTripsAndStops(device, from, to, TripReportItem.class);
+ DeviceReportSection deviceTrips = new DeviceReportSection();
+ deviceTrips.setDeviceName(device.getName());
+ sheetNames.add(WorkbookUtil.createSafeSheetName(deviceTrips.getDeviceName()));
+ if (device.getGroupId() > 0) {
+ Group group = storage.getObject(Group.class, new Request(
+ new Columns.All(), new Condition.Equals("id", device.getGroupId())));
+ if (group != null) {
+ deviceTrips.setGroupName(group.getName());
+ }
+ }
+ deviceTrips.setObjects(trips);
+ devicesTrips.add(deviceTrips);
+ }
+
+ File file = Paths.get(config.getString(Keys.TEMPLATES_ROOT), "export", "trips.xlsx").toFile();
+ try (InputStream inputStream = new FileInputStream(file)) {
+ var context = reportUtils.initializeContext(userId);
+ context.putVar("devices", devicesTrips);
+ context.putVar("sheetNames", sheetNames);
+ context.putVar("from", from);
+ context.putVar("to", to);
+ reportUtils.processTemplateWithSheets(inputStream, outputStream, context);
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/common/ExpressionEvaluatorFactory.java b/src/main/java/org/traccar/reports/common/ExpressionEvaluatorFactory.java
new file mode 100644
index 000000000..8b139a572
--- /dev/null
+++ b/src/main/java/org/traccar/reports/common/ExpressionEvaluatorFactory.java
@@ -0,0 +1,58 @@
+package org.traccar.reports.common;
+
+import org.apache.commons.jexl3.JexlBuilder;
+import org.apache.commons.jexl3.introspection.JexlPermissions;
+import org.jxls.expression.ExpressionEvaluator;
+import org.jxls.expression.JexlExpressionEvaluator;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public class ExpressionEvaluatorFactory implements org.jxls.expression.ExpressionEvaluatorFactory {
+
+ private final JexlPermissions permissions = new JexlPermissions() {
+ @Override
+ public boolean allow(Package pack) {
+ return true;
+ }
+
+ @Override
+ public boolean allow(Class<?> clazz) {
+ return true;
+ }
+
+ @Override
+ public boolean allow(Constructor<?> ctor) {
+ return true;
+ }
+
+ @Override
+ public boolean allow(Method method) {
+ return true;
+ }
+
+ @Override
+ public boolean allow(Field field) {
+ return true;
+ }
+
+ @Override
+ public JexlPermissions compose(String... src) {
+ return this;
+ }
+ };
+
+ @Override
+ public ExpressionEvaluator createExpressionEvaluator(String expression) {
+ JexlExpressionEvaluator expressionEvaluator = expression == null
+ ? new JexlExpressionEvaluator()
+ : new JexlExpressionEvaluator(expression);
+ expressionEvaluator.setJexlEngine(new JexlBuilder()
+ .silent(true)
+ .strict(false)
+ .permissions(permissions)
+ .create());
+ return expressionEvaluator;
+ }
+}
diff --git a/src/main/java/org/traccar/reports/common/ReportExecutor.java b/src/main/java/org/traccar/reports/common/ReportExecutor.java
new file mode 100644
index 000000000..aed4b8c23
--- /dev/null
+++ b/src/main/java/org/traccar/reports/common/ReportExecutor.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.reports.common;
+
+import org.traccar.storage.StorageException;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public interface ReportExecutor {
+ void execute(OutputStream stream) throws StorageException, IOException;
+}
diff --git a/src/main/java/org/traccar/reports/common/ReportMailer.java b/src/main/java/org/traccar/reports/common/ReportMailer.java
new file mode 100644
index 000000000..9fb30fe9f
--- /dev/null
+++ b/src/main/java/org/traccar/reports/common/ReportMailer.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.reports.common;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.api.security.PermissionsService;
+import org.traccar.mail.MailManager;
+import org.traccar.model.User;
+import org.traccar.storage.StorageException;
+
+import jakarta.activation.DataHandler;
+import jakarta.inject.Inject;
+import jakarta.mail.MessagingException;
+import jakarta.mail.internet.MimeBodyPart;
+import jakarta.mail.util.ByteArrayDataSource;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class ReportMailer {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ReportMailer.class);
+
+ private final PermissionsService permissionsService;
+ private final MailManager mailManager;
+
+ @Inject
+ public ReportMailer(PermissionsService permissionsService, MailManager mailManager) {
+ this.permissionsService = permissionsService;
+ this.mailManager = mailManager;
+ }
+
+ public void sendAsync(long userId, ReportExecutor executor) {
+ new Thread(() -> {
+ try {
+ var stream = new ByteArrayOutputStream();
+ executor.execute(stream);
+
+ MimeBodyPart attachment = new MimeBodyPart();
+ attachment.setFileName("report.xlsx");
+ attachment.setDataHandler(new DataHandler(new ByteArrayDataSource(
+ stream.toByteArray(), "application/octet-stream")));
+
+ User user = permissionsService.getUser(userId);
+ mailManager.sendMessage(user, false, "Report", "The report is in the attachment.", attachment);
+ } catch (StorageException | IOException | MessagingException e) {
+ LOGGER.warn("Email report failed", e);
+ }
+ }).start();
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java
new file mode 100644
index 000000000..43db82708
--- /dev/null
+++ b/src/main/java/org/traccar/reports/common/ReportUtils.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@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.reports.common;
+
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.tools.generic.DateTool;
+import org.apache.velocity.tools.generic.NumberTool;
+import org.jxls.area.Area;
+import org.jxls.builder.xls.XlsCommentAreaBuilder;
+import org.jxls.common.CellRef;
+import org.jxls.formula.StandardFormulaProcessor;
+import org.jxls.transform.Transformer;
+import org.jxls.transform.poi.PoiTransformer;
+import org.jxls.util.TransformerFactory;
+import org.traccar.api.security.PermissionsService;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.geocoder.Geocoder;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.helper.model.AttributeUtil;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.helper.model.UserUtil;
+import org.traccar.model.BaseModel;
+import org.traccar.model.Device;
+import org.traccar.model.Driver;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+import org.traccar.model.User;
+import org.traccar.reports.model.BaseReportItem;
+import org.traccar.reports.model.StopReportItem;
+import org.traccar.reports.model.TripReportItem;
+import org.traccar.session.state.MotionProcessor;
+import org.traccar.session.state.MotionState;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Order;
+import org.traccar.storage.query.Request;
+
+import jakarta.annotation.Nullable;
+import jakarta.inject.Inject;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class ReportUtils {
+
+ private final Config config;
+ private final Storage storage;
+ private final PermissionsService permissionsService;
+ private final VelocityEngine velocityEngine;
+ private final Geocoder geocoder;
+
+ @Inject
+ public ReportUtils(
+ Config config, Storage storage, PermissionsService permissionsService,
+ VelocityEngine velocityEngine, @Nullable Geocoder geocoder) {
+ this.config = config;
+ this.storage = storage;
+ this.permissionsService = permissionsService;
+ this.velocityEngine = velocityEngine;
+ this.geocoder = geocoder;
+ }
+
+ public <T extends BaseModel> T getObject(
+ long userId, Class<T> clazz, long objectId) throws StorageException, SecurityException {
+ return storage.getObject(clazz, new Request(
+ new Columns.All(),
+ new Condition.And(
+ new Condition.Equals("id", objectId),
+ new Condition.Permission(User.class, userId, clazz))));
+ }
+
+ public void checkPeriodLimit(Date from, Date to) {
+ long limit = config.getLong(Keys.REPORT_PERIOD_LIMIT) * 1000;
+ if (limit > 0 && to.getTime() - from.getTime() > limit) {
+ throw new IllegalArgumentException("Time period exceeds the limit");
+ }
+ }
+
+ public double calculateFuel(Position firstPosition, Position lastPosition) {
+
+ if (firstPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null
+ && lastPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null) {
+
+ BigDecimal value = BigDecimal.valueOf(firstPosition.getDouble(Position.KEY_FUEL_LEVEL)
+ - lastPosition.getDouble(Position.KEY_FUEL_LEVEL));
+ return value.setScale(1, RoundingMode.HALF_EVEN).doubleValue();
+ }
+ return 0;
+ }
+
+ public String findDriver(Position firstPosition, Position lastPosition) {
+ if (firstPosition.hasAttribute(Position.KEY_DRIVER_UNIQUE_ID)) {
+ return firstPosition.getString(Position.KEY_DRIVER_UNIQUE_ID);
+ } else if (lastPosition.hasAttribute(Position.KEY_DRIVER_UNIQUE_ID)) {
+ return lastPosition.getString(Position.KEY_DRIVER_UNIQUE_ID);
+ }
+ return null;
+ }
+
+ public String findDriverName(String driverUniqueId) throws StorageException {
+ if (driverUniqueId != null) {
+ Driver driver = storage.getObject(Driver.class, new Request(
+ new Columns.All(),
+ new Condition.Equals("uniqueId", driverUniqueId)));
+ if (driver != null) {
+ return driver.getName();
+ }
+ }
+ return null;
+ }
+
+ public org.jxls.common.Context initializeContext(long userId) throws StorageException {
+ var server = permissionsService.getServer();
+ var user = permissionsService.getUser(userId);
+ var context = PoiTransformer.createInitialContext();
+ context.putVar("distanceUnit", UserUtil.getDistanceUnit(server, user));
+ context.putVar("speedUnit", UserUtil.getSpeedUnit(server, user));
+ context.putVar("volumeUnit", UserUtil.getVolumeUnit(server, user));
+ context.putVar("webUrl", velocityEngine.getProperty("web.url"));
+ context.putVar("dateTool", new DateTool());
+ context.putVar("numberTool", new NumberTool());
+ context.putVar("timezone", UserUtil.getTimezone(server, user));
+ context.putVar("locale", Locale.getDefault());
+ context.putVar("bracketsRegex", "[\\{\\}\"]");
+ return context;
+ }
+
+ public void processTemplateWithSheets(
+ InputStream templateStream, OutputStream targetStream, org.jxls.common.Context context) throws IOException {
+
+ Transformer transformer = TransformerFactory.createTransformer(templateStream, targetStream);
+ List<Area> xlsAreas = new XlsCommentAreaBuilder(transformer).build();
+ for (Area xlsArea : xlsAreas) {
+ xlsArea.applyAt(new CellRef(xlsArea.getStartCellRef().getCellName()), context);
+ xlsArea.setFormulaProcessor(new StandardFormulaProcessor());
+ xlsArea.processFormulas();
+ }
+ transformer.deleteSheet(xlsAreas.get(0).getStartCellRef().getSheetName());
+ transformer.write();
+ }
+
+ private TripReportItem calculateTrip(
+ Device device, Position startTrip, Position endTrip, double maxSpeed,
+ boolean ignoreOdometer) throws StorageException {
+
+ TripReportItem trip = new TripReportItem();
+
+ long tripDuration = endTrip.getFixTime().getTime() - startTrip.getFixTime().getTime();
+ long deviceId = startTrip.getDeviceId();
+ trip.setDeviceId(deviceId);
+ trip.setDeviceName(device.getName());
+
+ trip.setStartPositionId(startTrip.getId());
+ trip.setStartLat(startTrip.getLatitude());
+ trip.setStartLon(startTrip.getLongitude());
+ trip.setStartTime(startTrip.getFixTime());
+ String startAddress = startTrip.getAddress();
+ if (startAddress == null && geocoder != null && config.getBoolean(Keys.GEOCODER_ON_REQUEST)) {
+ startAddress = geocoder.getAddress(startTrip.getLatitude(), startTrip.getLongitude(), null);
+ }
+ trip.setStartAddress(startAddress);
+
+ trip.setEndPositionId(endTrip.getId());
+ trip.setEndLat(endTrip.getLatitude());
+ trip.setEndLon(endTrip.getLongitude());
+ trip.setEndTime(endTrip.getFixTime());
+ String endAddress = endTrip.getAddress();
+ if (endAddress == null && geocoder != null && config.getBoolean(Keys.GEOCODER_ON_REQUEST)) {
+ endAddress = geocoder.getAddress(endTrip.getLatitude(), endTrip.getLongitude(), null);
+ }
+ trip.setEndAddress(endAddress);
+
+ trip.setDistance(PositionUtil.calculateDistance(startTrip, endTrip, !ignoreOdometer));
+ trip.setDuration(tripDuration);
+ if (tripDuration > 0) {
+ trip.setAverageSpeed(UnitsConverter.knotsFromMps(trip.getDistance() * 1000 / tripDuration));
+ }
+ trip.setMaxSpeed(maxSpeed);
+ trip.setSpentFuel(calculateFuel(startTrip, endTrip));
+
+ trip.setDriverUniqueId(findDriver(startTrip, endTrip));
+ trip.setDriverName(findDriverName(trip.getDriverUniqueId()));
+
+ if (!ignoreOdometer
+ && startTrip.getDouble(Position.KEY_ODOMETER) != 0
+ && endTrip.getDouble(Position.KEY_ODOMETER) != 0) {
+ trip.setStartOdometer(startTrip.getDouble(Position.KEY_ODOMETER));
+ trip.setEndOdometer(endTrip.getDouble(Position.KEY_ODOMETER));
+ } else {
+ trip.setStartOdometer(startTrip.getDouble(Position.KEY_TOTAL_DISTANCE));
+ trip.setEndOdometer(endTrip.getDouble(Position.KEY_TOTAL_DISTANCE));
+ }
+
+ return trip;
+ }
+
+ private StopReportItem calculateStop(
+ Device device, Position startStop, Position endStop, boolean ignoreOdometer) {
+
+ StopReportItem stop = new StopReportItem();
+
+ long deviceId = startStop.getDeviceId();
+ stop.setDeviceId(deviceId);
+ stop.setDeviceName(device.getName());
+
+ stop.setPositionId(startStop.getId());
+ stop.setLatitude(startStop.getLatitude());
+ stop.setLongitude(startStop.getLongitude());
+ stop.setStartTime(startStop.getFixTime());
+ String address = startStop.getAddress();
+ if (address == null && geocoder != null && config.getBoolean(Keys.GEOCODER_ON_REQUEST)) {
+ address = geocoder.getAddress(stop.getLatitude(), stop.getLongitude(), null);
+ }
+ stop.setAddress(address);
+
+ stop.setEndTime(endStop.getFixTime());
+
+ long stopDuration = endStop.getFixTime().getTime() - startStop.getFixTime().getTime();
+ stop.setDuration(stopDuration);
+ stop.setSpentFuel(calculateFuel(startStop, endStop));
+
+ if (startStop.hasAttribute(Position.KEY_HOURS) && endStop.hasAttribute(Position.KEY_HOURS)) {
+ stop.setEngineHours(endStop.getLong(Position.KEY_HOURS) - startStop.getLong(Position.KEY_HOURS));
+ }
+
+ if (!ignoreOdometer
+ && startStop.getDouble(Position.KEY_ODOMETER) != 0
+ && endStop.getDouble(Position.KEY_ODOMETER) != 0) {
+ stop.setStartOdometer(startStop.getDouble(Position.KEY_ODOMETER));
+ stop.setEndOdometer(endStop.getDouble(Position.KEY_ODOMETER));
+ } else {
+ stop.setStartOdometer(startStop.getDouble(Position.KEY_TOTAL_DISTANCE));
+ stop.setEndOdometer(endStop.getDouble(Position.KEY_TOTAL_DISTANCE));
+ }
+
+ return stop;
+
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T extends BaseReportItem> T calculateTripOrStop(
+ Device device, Position startPosition, Position endPosition, double maxSpeed,
+ boolean ignoreOdometer, Class<T> reportClass) throws StorageException {
+
+ if (reportClass.equals(TripReportItem.class)) {
+ return (T) calculateTrip(device, startPosition, endPosition, maxSpeed, ignoreOdometer);
+ } else {
+ return (T) calculateStop(device, startPosition, endPosition, ignoreOdometer);
+ }
+ }
+
+ private boolean isMoving(List<Position> positions, int index, TripsConfig tripsConfig) {
+ if (tripsConfig.getMinimalNoDataDuration() > 0) {
+ boolean beforeGap = index < positions.size() - 1
+ && positions.get(index + 1).getFixTime().getTime() - positions.get(index).getFixTime().getTime()
+ >= tripsConfig.getMinimalNoDataDuration();
+ boolean afterGap = index > 0
+ && positions.get(index).getFixTime().getTime() - positions.get(index - 1).getFixTime().getTime()
+ >= tripsConfig.getMinimalNoDataDuration();
+ if (beforeGap || afterGap) {
+ return false;
+ }
+ }
+ return positions.get(index).getBoolean(Position.KEY_MOTION);
+ }
+
+ public <T extends BaseReportItem> List<T> detectTripsAndStops(
+ Device device, Date from, Date to, Class<T> reportClass) throws StorageException {
+
+ long threshold = config.getLong(Keys.REPORT_FAST_THRESHOLD);
+ if (Duration.between(from.toInstant(), to.toInstant()).toSeconds() > threshold) {
+ return fastTripsAndStops(device, from, to, reportClass);
+ } else {
+ return slowTripsAndStops(device, from, to, reportClass);
+ }
+ }
+
+ public <T extends BaseReportItem> List<T> slowTripsAndStops(
+ Device device, Date from, Date to, Class<T> reportClass) throws StorageException {
+
+ List<T> result = new ArrayList<>();
+ TripsConfig tripsConfig = new TripsConfig(
+ new AttributeUtil.StorageProvider(config, storage, permissionsService, device));
+ boolean ignoreOdometer = config.getBoolean(Keys.REPORT_IGNORE_ODOMETER);
+
+ var positions = PositionUtil.getPositions(storage, device.getId(), from, to);
+ if (!positions.isEmpty()) {
+ boolean trips = reportClass.equals(TripReportItem.class);
+
+ MotionState motionState = new MotionState();
+ boolean initialValue = isMoving(positions, 0, tripsConfig);
+ motionState.setMotionStreak(initialValue);
+ motionState.setMotionState(initialValue);
+
+ boolean detected = trips == motionState.getMotionState();
+ double maxSpeed = 0;
+ int startEventIndex = detected ? 0 : -1;
+ int startNoEventIndex = -1;
+ for (int i = 0; i < positions.size(); i++) {
+ boolean motion = isMoving(positions, i, tripsConfig);
+ if (motionState.getMotionState() != motion) {
+ if (motion == trips) {
+ if (!detected) {
+ startEventIndex = i;
+ maxSpeed = positions.get(i).getSpeed();
+ }
+ startNoEventIndex = -1;
+ } else {
+ startNoEventIndex = i;
+ }
+ } else {
+ maxSpeed = Math.max(maxSpeed, positions.get(i).getSpeed());
+ }
+
+ MotionProcessor.updateState(motionState, positions.get(i), motion, tripsConfig);
+ if (motionState.getEvent() != null) {
+ if (motion == trips) {
+ detected = true;
+ startNoEventIndex = -1;
+ } else if (startEventIndex >= 0 && startNoEventIndex >= 0) {
+ result.add(calculateTripOrStop(
+ device, positions.get(startEventIndex), positions.get(startNoEventIndex),
+ maxSpeed, ignoreOdometer, reportClass));
+ detected = false;
+ startEventIndex = -1;
+ startNoEventIndex = -1;
+ }
+ }
+ }
+ if (detected & startEventIndex >= 0 && startEventIndex < positions.size() - 1) {
+ int endIndex = startNoEventIndex >= 0 ? startNoEventIndex : positions.size() - 1;
+ result.add(calculateTripOrStop(
+ device, positions.get(startEventIndex), positions.get(endIndex),
+ maxSpeed, ignoreOdometer, reportClass));
+ }
+ }
+
+ return result;
+ }
+
+ public <T extends BaseReportItem> List<T> fastTripsAndStops(
+ Device device, Date from, Date to, Class<T> reportClass) throws StorageException {
+
+ List<T> result = new ArrayList<>();
+ boolean ignoreOdometer = config.getBoolean(Keys.REPORT_IGNORE_ODOMETER);
+ boolean trips = reportClass.equals(TripReportItem.class);
+ Set<String> filter = Set.of(Event.TYPE_DEVICE_MOVING, Event.TYPE_DEVICE_STOPPED);
+
+ var events = storage.getObjects(Event.class, new Request(
+ new Columns.All(),
+ new Condition.And(
+ new Condition.Equals("deviceId", device.getId()),
+ new Condition.Between("eventTime", "from", from, "to", to)),
+ new Order("eventTime")));
+ var filteredEvents = events.stream()
+ .filter(event -> filter.contains(event.getType()))
+ .collect(Collectors.toList());
+
+ Event startEvent = null;
+ for (Event event : filteredEvents) {
+ boolean motion = event.getType().equals(Event.TYPE_DEVICE_MOVING);
+ if (motion == trips) {
+ startEvent = event;
+ } else if (startEvent != null) {
+ Position startPosition = storage.getObject(Position.class, new Request(
+ new Columns.All(), new Condition.Equals("id", startEvent.getPositionId())));
+ Position endPosition = storage.getObject(Position.class, new Request(
+ new Columns.All(), new Condition.Equals("id", event.getPositionId())));
+ if (startPosition != null && endPosition != null) {
+ result.add(calculateTripOrStop(
+ device, startPosition, endPosition, 0, ignoreOdometer, reportClass));
+ }
+ startEvent = null;
+ }
+ }
+
+ return result;
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/common/TripsConfig.java b/src/main/java/org/traccar/reports/common/TripsConfig.java
new file mode 100644
index 000000000..2792114d4
--- /dev/null
+++ b/src/main/java/org/traccar/reports/common/TripsConfig.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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.reports.common;
+
+import org.traccar.config.Keys;
+import org.traccar.helper.model.AttributeUtil;
+
+public class TripsConfig {
+
+ public TripsConfig(AttributeUtil.Provider attributeProvider) {
+ this(
+ AttributeUtil.lookup(attributeProvider, Keys.REPORT_TRIP_MINIMAL_TRIP_DISTANCE),
+ AttributeUtil.lookup(attributeProvider, Keys.REPORT_TRIP_MINIMAL_TRIP_DURATION) * 1000,
+ AttributeUtil.lookup(attributeProvider, Keys.REPORT_TRIP_MINIMAL_PARKING_DURATION) * 1000,
+ AttributeUtil.lookup(attributeProvider, Keys.REPORT_TRIP_MINIMAL_NO_DATA_DURATION) * 1000,
+ AttributeUtil.lookup(attributeProvider, Keys.REPORT_TRIP_USE_IGNITION));
+ }
+
+ public TripsConfig(
+ double minimalTripDistance, long minimalTripDuration, long minimalParkingDuration,
+ long minimalNoDataDuration, boolean useIgnition) {
+ this.minimalTripDistance = minimalTripDistance;
+ this.minimalTripDuration = minimalTripDuration;
+ this.minimalParkingDuration = minimalParkingDuration;
+ this.minimalNoDataDuration = minimalNoDataDuration;
+ this.useIgnition = useIgnition;
+ }
+
+ private final double minimalTripDistance;
+
+ public double getMinimalTripDistance() {
+ return minimalTripDistance;
+ }
+
+ private final long minimalTripDuration;
+
+ public long getMinimalTripDuration() {
+ return minimalTripDuration;
+ }
+
+ private final long minimalParkingDuration;
+
+ public long getMinimalParkingDuration() {
+ return minimalParkingDuration;
+ }
+
+ private final long minimalNoDataDuration;
+
+ public long getMinimalNoDataDuration() {
+ return minimalNoDataDuration;
+ }
+
+ private final boolean useIgnition;
+
+ public boolean getUseIgnition() {
+ return useIgnition;
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/model/BaseReport.java b/src/main/java/org/traccar/reports/model/BaseReportItem.java
index 928c0557d..6e270dfe3 100644
--- a/src/main/java/org/traccar/reports/model/BaseReport.java
+++ b/src/main/java/org/traccar/reports/model/BaseReportItem.java
@@ -18,7 +18,7 @@ package org.traccar.reports.model;
import java.util.Date;
-public class BaseReport {
+public class BaseReportItem {
private long deviceId;
diff --git a/src/main/java/org/traccar/reports/model/CombinedReportItem.java b/src/main/java/org/traccar/reports/model/CombinedReportItem.java
new file mode 100644
index 000000000..810e00916
--- /dev/null
+++ b/src/main/java/org/traccar/reports/model/CombinedReportItem.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.reports.model;
+
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+import java.util.List;
+
+public class CombinedReportItem {
+
+ private long deviceId;
+
+ public long getDeviceId() {
+ return deviceId;
+ }
+
+ public void setDeviceId(long deviceId) {
+ this.deviceId = deviceId;
+ }
+
+ private List<double[]> route;
+
+ public List<double[]> getRoute() {
+ return route;
+ }
+
+ public void setRoute(List<double[]> route) {
+ this.route = route;
+ }
+
+ private List<Event> events;
+
+ public List<Event> getEvents() {
+ return events;
+ }
+
+ public void setEvents(List<Event> events) {
+ this.events = events;
+ }
+
+ private List<Position> positions;
+
+ public List<Position> getPositions() {
+ return positions;
+ }
+
+ public void setPositions(List<Position> positions) {
+ this.positions = positions;
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/model/DeviceReport.java b/src/main/java/org/traccar/reports/model/DeviceReportSection.java
index 932753d15..ffc4d774f 100644
--- a/src/main/java/org/traccar/reports/model/DeviceReport.java
+++ b/src/main/java/org/traccar/reports/model/DeviceReportSection.java
@@ -20,7 +20,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-public class DeviceReport {
+public class DeviceReportSection {
private String deviceName;
diff --git a/src/main/java/org/traccar/reports/model/StopReport.java b/src/main/java/org/traccar/reports/model/StopReportItem.java
index e20f2c503..3c35bdc21 100644
--- a/src/main/java/org/traccar/reports/model/StopReport.java
+++ b/src/main/java/org/traccar/reports/model/StopReportItem.java
@@ -16,7 +16,7 @@
*/
package org.traccar.reports.model;
-public class StopReport extends BaseReport {
+public class StopReportItem extends BaseReportItem {
private long positionId;
diff --git a/src/main/java/org/traccar/reports/model/SummaryReport.java b/src/main/java/org/traccar/reports/model/SummaryReportItem.java
index 886f8b9e2..44a15cf1d 100644
--- a/src/main/java/org/traccar/reports/model/SummaryReport.java
+++ b/src/main/java/org/traccar/reports/model/SummaryReportItem.java
@@ -16,7 +16,7 @@
*/
package org.traccar.reports.model;
-public class SummaryReport extends BaseReport {
+public class SummaryReportItem extends BaseReportItem {
private long engineHours; // milliseconds
diff --git a/src/main/java/org/traccar/reports/model/TripReport.java b/src/main/java/org/traccar/reports/model/TripReportItem.java
index 151c34bd5..332a34cca 100644
--- a/src/main/java/org/traccar/reports/model/TripReport.java
+++ b/src/main/java/org/traccar/reports/model/TripReportItem.java
@@ -16,7 +16,7 @@
*/
package org.traccar.reports.model;
-public class TripReport extends BaseReport {
+public class TripReportItem extends BaseReportItem {
private long startPositionId;
diff --git a/src/main/java/org/traccar/reports/model/TripsConfig.java b/src/main/java/org/traccar/reports/model/TripsConfig.java
deleted file mode 100644
index 0f0c615d3..000000000
--- a/src/main/java/org/traccar/reports/model/TripsConfig.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.reports.model;
-
-public class TripsConfig {
-
- public TripsConfig() {
- }
-
- public TripsConfig(double minimalTripDistance, long minimalTripDuration, long minimalParkingDuration,
- long minimalNoDataDuration, boolean useIgnition, boolean processInvalidPositions, double speedThreshold) {
- this.minimalTripDistance = minimalTripDistance;
- this.minimalTripDuration = minimalTripDuration;
- this.minimalParkingDuration = minimalParkingDuration;
- this.minimalNoDataDuration = minimalNoDataDuration;
- this.useIgnition = useIgnition;
- this.processInvalidPositions = processInvalidPositions;
- this.speedThreshold = speedThreshold;
- }
-
- private double minimalTripDistance;
-
- public double getMinimalTripDistance() {
- return minimalTripDistance;
- }
-
- public void setMinimalTripDistance(double minimalTripDistance) {
- this.minimalTripDistance = minimalTripDistance;
- }
-
- private long minimalTripDuration;
-
- public long getMinimalTripDuration() {
- return minimalTripDuration;
- }
-
- public void setMinimalTripDuration(long minimalTripDuration) {
- this.minimalTripDuration = minimalTripDuration;
- }
-
- private long minimalParkingDuration;
-
- public long getMinimalParkingDuration() {
- return minimalParkingDuration;
- }
-
- public void setMinimalParkingDuration(long minimalParkingDuration) {
- this.minimalParkingDuration = minimalParkingDuration;
- }
-
- private long minimalNoDataDuration;
-
- public long getMinimalNoDataDuration() {
- return minimalNoDataDuration;
- }
-
- public void setMinimalNoDataDuration(long minimalNoDataDuration) {
- this.minimalNoDataDuration = minimalNoDataDuration;
- }
-
- private boolean useIgnition;
-
- public boolean getUseIgnition() {
- return useIgnition;
- }
-
- public void setUseIgnition(boolean useIgnition) {
- this.useIgnition = useIgnition;
- }
-
- private boolean processInvalidPositions;
-
- public boolean getProcessInvalidPositions() {
- return processInvalidPositions;
- }
-
- public void setProcessInvalidPositions(boolean processInvalidPositions) {
- this.processInvalidPositions = processInvalidPositions;
- }
-
- private double speedThreshold;
-
- public double getSpeedThreshold() {
- return speedThreshold;
- }
-
- public void setSpeedThreshold(double speedThreshold) {
- this.speedThreshold = speedThreshold;
- }
-
-}
diff --git a/src/main/java/org/traccar/schedule/ScheduleManager.java b/src/main/java/org/traccar/schedule/ScheduleManager.java
index 7a3d33b85..07cdb1fe1 100644
--- a/src/main/java/org/traccar/schedule/ScheduleManager.java
+++ b/src/main/java/org/traccar/schedule/ScheduleManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2020 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,22 +15,35 @@
*/
package org.traccar.schedule;
+import com.google.inject.Injector;
import org.traccar.LifecycleObject;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
+@Singleton
public class ScheduleManager implements LifecycleObject {
+ private final Injector injector;
private ScheduledExecutorService executor;
+ @Inject
+ public ScheduleManager(Injector injector) {
+ this.injector = injector;
+ }
+
@Override
public void start() {
executor = Executors.newSingleThreadScheduledExecutor();
-
- new TaskDeviceInactivityCheck().schedule(executor);
- new TaskWebSocketKeepalive().schedule(executor);
- new TaskHealthCheck().schedule(executor);
+ var tasks = List.of(
+ TaskReports.class,
+ TaskDeviceInactivityCheck.class,
+ TaskWebSocketKeepalive.class,
+ TaskHealthCheck.class);
+ tasks.forEach(task -> injector.getInstance(task).schedule(executor));
}
@Override
diff --git a/src/main/java/org/traccar/database/OrderManager.java b/src/main/java/org/traccar/schedule/ScheduleTask.java
index c3253e52f..1b537213b 100644
--- a/src/main/java/org/traccar/database/OrderManager.java
+++ b/src/main/java/org/traccar/schedule/ScheduleTask.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Anton Tananaev (anton@traccar.org)
+ * 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.
@@ -13,14 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.database;
+package org.traccar.schedule;
-import org.traccar.model.Order;
-
-public class OrderManager extends ExtendedObjectManager<Order> {
-
- public OrderManager(DataManager dataManager) {
- super(dataManager, Order.class);
- }
+import java.util.concurrent.ScheduledExecutorService;
+public interface ScheduleTask extends Runnable {
+ void schedule(ScheduledExecutorService executor);
}
diff --git a/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java b/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java
index 80641d7d4..8e45568d5 100644
--- a/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java
+++ b/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2020 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,17 +15,28 @@
*/
package org.traccar.schedule;
-import org.traccar.Context;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.database.NotificationManager;
import org.traccar.model.Device;
import org.traccar.model.Event;
+import org.traccar.model.Group;
import org.traccar.model.Position;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Request;
+import jakarta.inject.Inject;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
-public class TaskDeviceInactivityCheck implements Runnable {
+public class TaskDeviceInactivityCheck implements ScheduleTask {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TaskDeviceInactivityCheck.class);
public static final String ATTRIBUTE_DEVICE_INACTIVITY_START = "deviceInactivityStart";
public static final String ATTRIBUTE_DEVICE_INACTIVITY_PERIOD = "deviceInactivityPeriod";
@@ -33,6 +44,16 @@ public class TaskDeviceInactivityCheck implements Runnable {
private static final long CHECK_PERIOD_MINUTES = 15;
+ private final Storage storage;
+ private final NotificationManager notificationManager;
+
+ @Inject
+ public TaskDeviceInactivityCheck(Storage storage, NotificationManager notificationManager) {
+ this.storage = storage;
+ this.notificationManager = notificationManager;
+ }
+
+ @Override
public void schedule(ScheduledExecutorService executor) {
executor.scheduleAtFixedRate(this, CHECK_PERIOD_MINUTES, CHECK_PERIOD_MINUTES, TimeUnit.MINUTES);
}
@@ -43,19 +64,47 @@ public class TaskDeviceInactivityCheck implements Runnable {
long checkPeriod = TimeUnit.MINUTES.toMillis(CHECK_PERIOD_MINUTES);
Map<Event, Position> events = new HashMap<>();
- for (Device device : Context.getDeviceManager().getAllDevices()) {
- if (device.getLastUpdate() != null && checkDevice(device, currentTime, checkPeriod)) {
- Event event = new Event(Event.TYPE_DEVICE_INACTIVE, device.getId());
- event.set(ATTRIBUTE_LAST_UPDATE, device.getLastUpdate().getTime());
- events.put(event, null);
+
+ try {
+ Map<Long, Group> groups = storage.getObjects(Group.class, new Request(new Columns.All()))
+ .stream().collect(Collectors.toMap(Group::getId, group -> group));
+ for (Device device : storage.getObjects(Device.class, new Request(new Columns.All()))) {
+ if (device.getLastUpdate() != null && checkDevice(device, groups, currentTime, checkPeriod)) {
+ Event event = new Event(Event.TYPE_DEVICE_INACTIVE, device.getId());
+ event.set(ATTRIBUTE_LAST_UPDATE, device.getLastUpdate().getTime());
+ events.put(event, null);
+ }
}
+ } catch (StorageException e) {
+ LOGGER.warn("Database error", e);
}
- Context.getNotificationManager().updateEvents(events);
+ notificationManager.updateEvents(events);
+ }
+
+ private long getAttribute(Device device, Map<Long, Group> groups, String key) {
+ long deviceValue = device.getLong(key);
+ if (deviceValue > 0) {
+ return deviceValue;
+ } else {
+ long groupId = device.getGroupId();
+ while (groupId > 0) {
+ Group group = groups.get(groupId);
+ if (group == null) {
+ return 0;
+ }
+ long groupValue = group.getLong(key);
+ if (groupValue > 0) {
+ return groupValue;
+ }
+ groupId = group.getGroupId();
+ }
+ return 0;
+ }
}
- private boolean checkDevice(Device device, long currentTime, long checkPeriod) {
- long deviceInactivityStart = device.getLong(ATTRIBUTE_DEVICE_INACTIVITY_START);
+ private boolean checkDevice(Device device, Map<Long, Group> groups, long currentTime, long checkPeriod) {
+ long deviceInactivityStart = getAttribute(device, groups, ATTRIBUTE_DEVICE_INACTIVITY_START);
if (deviceInactivityStart > 0) {
long timeThreshold = device.getLastUpdate().getTime() + deviceInactivityStart;
if (currentTime >= timeThreshold) {
@@ -64,7 +113,7 @@ public class TaskDeviceInactivityCheck implements Runnable {
return true;
}
- long deviceInactivityPeriod = device.getLong(ATTRIBUTE_DEVICE_INACTIVITY_PERIOD);
+ long deviceInactivityPeriod = getAttribute(device, groups, ATTRIBUTE_DEVICE_INACTIVITY_PERIOD);
if (deviceInactivityPeriod > 0) {
long count = (currentTime - timeThreshold - 1) / deviceInactivityPeriod;
timeThreshold += count * deviceInactivityPeriod;
diff --git a/src/main/java/org/traccar/schedule/TaskHealthCheck.java b/src/main/java/org/traccar/schedule/TaskHealthCheck.java
index 087cd3e63..abdc5af48 100644
--- a/src/main/java/org/traccar/schedule/TaskHealthCheck.java
+++ b/src/main/java/org/traccar/schedule/TaskHealthCheck.java
@@ -19,23 +19,31 @@ import com.sun.jna.Library;
import com.sun.jna.Native;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.Context;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.client.Client;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-public class TaskHealthCheck implements Runnable {
+public class TaskHealthCheck implements ScheduleTask {
private static final Logger LOGGER = LoggerFactory.getLogger(TaskHealthCheck.class);
+ private final Config config;
+ private final Client client;
+
private SystemD systemD;
private boolean enabled;
private long period;
- public TaskHealthCheck() {
- if (!Context.getConfig().getBoolean(Keys.WEB_DISABLE_HEALTH_CHECK)
+ @Inject
+ public TaskHealthCheck(Config config, Client client) {
+ this.config = config;
+ this.client = client;
+ if (!config.getBoolean(Keys.WEB_DISABLE_HEALTH_CHECK)
&& System.getProperty("os.name").toLowerCase().startsWith("linux")) {
try {
systemD = Native.load("systemd", SystemD.class);
@@ -54,11 +62,12 @@ public class TaskHealthCheck implements Runnable {
}
private String getUrl() {
- String address = Context.getConfig().getString(Keys.WEB_ADDRESS, "localhost");
- int port = Context.getConfig().getInteger(Keys.WEB_PORT);
+ String address = config.getString(Keys.WEB_ADDRESS, "localhost");
+ int port = config.getInteger(Keys.WEB_PORT);
return "http://" + address + ":" + port + "/api/server";
}
+ @Override
public void schedule(ScheduledExecutorService executor) {
if (enabled) {
executor.scheduleAtFixedRate(this, period, period, TimeUnit.MILLISECONDS);
@@ -68,7 +77,7 @@ public class TaskHealthCheck implements Runnable {
@Override
public void run() {
LOGGER.debug("Health check running");
- int status = Context.getClient().target(getUrl()).request().get().getStatus();
+ int status = client.target(getUrl()).request().get().getStatus();
if (status == 200) {
int result = systemD.sd_notify(0, "WATCHDOG=1");
if (result < 0) {
diff --git a/src/main/java/org/traccar/schedule/TaskReports.java b/src/main/java/org/traccar/schedule/TaskReports.java
new file mode 100644
index 000000000..30f20f437
--- /dev/null
+++ b/src/main/java/org/traccar/schedule/TaskReports.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.schedule;
+
+import com.google.inject.Injector;
+import com.google.inject.servlet.RequestScoper;
+import com.google.inject.servlet.ServletScopes;
+import net.fortuna.ical4j.model.Period;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.model.BaseModel;
+import org.traccar.model.Calendar;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.model.Report;
+import org.traccar.model.User;
+import org.traccar.reports.EventsReportProvider;
+import org.traccar.reports.RouteReportProvider;
+import org.traccar.reports.StopsReportProvider;
+import org.traccar.reports.SummaryReportProvider;
+import org.traccar.reports.TripsReportProvider;
+import org.traccar.reports.common.ReportMailer;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+public class TaskReports implements ScheduleTask {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TaskReports.class);
+
+ private static final long CHECK_PERIOD_MINUTES = 1;
+
+ private final Storage storage;
+ private final Injector injector;
+
+ @Inject
+ public TaskReports(Storage storage, Injector injector) {
+ this.storage = storage;
+ this.injector = injector;
+ }
+
+ @Override
+ public void schedule(ScheduledExecutorService executor) {
+ executor.scheduleAtFixedRate(this, CHECK_PERIOD_MINUTES, CHECK_PERIOD_MINUTES, TimeUnit.MINUTES);
+ }
+
+ @Override
+ public void run() {
+ Date currentCheck = new Date();
+ Date lastCheck = new Date(System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(CHECK_PERIOD_MINUTES));
+
+ try {
+ for (Report report : storage.getObjects(Report.class, new Request(new Columns.All()))) {
+ Calendar calendar = storage.getObject(Calendar.class, new Request(
+ new Columns.All(), new Condition.Equals("id", report.getCalendarId())));
+
+ var lastEvents = calendar.findPeriods(lastCheck);
+ var currentEvents = calendar.findPeriods(currentCheck);
+
+ if (!lastEvents.isEmpty() && currentEvents.isEmpty()) {
+ Period period = lastEvents.iterator().next();
+ RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap());
+ try (RequestScoper.CloseableScope ignored = scope.open()) {
+ executeReport(report, period.getStart(), period.getEnd());
+ }
+ }
+ }
+ } catch (StorageException e) {
+ LOGGER.warn("Scheduled reports error", e);
+ }
+ }
+
+ private void executeReport(Report report, Date from, Date to) throws StorageException {
+
+ var deviceIds = storage.getObjects(Device.class, new Request(
+ new Columns.Include("id"),
+ new Condition.Permission(Device.class, Report.class, report.getId())))
+ .stream().map(BaseModel::getId).collect(Collectors.toList());
+ var groupIds = storage.getObjects(Group.class, new Request(
+ new Columns.Include("id"),
+ new Condition.Permission(Group.class, Report.class, report.getId())))
+ .stream().map(BaseModel::getId).collect(Collectors.toList());
+ var users = storage.getObjects(User.class, new Request(
+ new Columns.Include("id"),
+ new Condition.Permission(User.class, Report.class, report.getId())));
+
+ ReportMailer reportMailer = injector.getInstance(ReportMailer.class);
+
+ for (User user : users) {
+ switch (report.getType()) {
+ case "events":
+ var eventsReportProvider = injector.getInstance(EventsReportProvider.class);
+ reportMailer.sendAsync(user.getId(), stream -> eventsReportProvider.getExcel(
+ stream, user.getId(), deviceIds, groupIds, List.of(), from, to));
+ break;
+ case "route":
+ var routeReportProvider = injector.getInstance(RouteReportProvider.class);
+ reportMailer.sendAsync(user.getId(), stream -> routeReportProvider.getExcel(
+ stream, user.getId(), deviceIds, groupIds, from, to));
+ break;
+ case "summary":
+ var summaryReportProvider = injector.getInstance(SummaryReportProvider.class);
+ reportMailer.sendAsync(user.getId(), stream -> summaryReportProvider.getExcel(
+ stream, user.getId(), deviceIds, groupIds, from, to, false));
+ break;
+ case "trips":
+ var tripsReportProvider = injector.getInstance(TripsReportProvider.class);
+ reportMailer.sendAsync(user.getId(), stream -> tripsReportProvider.getExcel(
+ stream, user.getId(), deviceIds, groupIds, from, to));
+ break;
+ case "stops":
+ var stopsReportProvider = injector.getInstance(StopsReportProvider.class);
+ reportMailer.sendAsync(user.getId(), stream -> stopsReportProvider.getExcel(
+ stream, user.getId(), deviceIds, groupIds, from, to));
+ break;
+ default:
+ LOGGER.warn("Unsupported report type {}", report.getType());
+ break;
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/schedule/TaskWebSocketKeepalive.java b/src/main/java/org/traccar/schedule/TaskWebSocketKeepalive.java
index 953b0efea..d9e0c6f0b 100644
--- a/src/main/java/org/traccar/schedule/TaskWebSocketKeepalive.java
+++ b/src/main/java/org/traccar/schedule/TaskWebSocketKeepalive.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2021 - 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,22 +15,31 @@
*/
package org.traccar.schedule;
-import org.traccar.Context;
+import org.traccar.session.ConnectionManager;
+import jakarta.inject.Inject;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-public class TaskWebSocketKeepalive implements Runnable {
+public class TaskWebSocketKeepalive implements ScheduleTask {
private static final long PERIOD_SECONDS = 55;
+ private final ConnectionManager connectionManager;
+
+ @Inject
+ public TaskWebSocketKeepalive(ConnectionManager connectionManager) {
+ this.connectionManager = connectionManager;
+ }
+
+ @Override
public void schedule(ScheduledExecutorService executor) {
executor.scheduleAtFixedRate(this, PERIOD_SECONDS, PERIOD_SECONDS, TimeUnit.SECONDS);
}
@Override
public void run() {
- Context.getConnectionManager().sendKeepalive();
+ connectionManager.sendKeepalive();
}
}
diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java
new file mode 100644
index 000000000..28214840d
--- /dev/null
+++ b/src/main/java/org/traccar/session/ConnectionManager.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2015 - 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.session;
+
+import io.netty.channel.Channel;
+import io.netty.util.Timeout;
+import io.netty.util.Timer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.Protocol;
+import org.traccar.broadcast.BroadcastInterface;
+import org.traccar.broadcast.BroadcastService;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.database.DeviceLookupService;
+import org.traccar.database.NotificationManager;
+import org.traccar.model.BaseModel;
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+import org.traccar.model.User;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+@Singleton
+public class ConnectionManager implements BroadcastInterface {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionManager.class);
+
+ private final long deviceTimeout;
+
+ private final Map<Long, DeviceSession> sessionsByDeviceId = new ConcurrentHashMap<>();
+ private final Map<Endpoint, Map<String, DeviceSession>> sessionsByEndpoint = new ConcurrentHashMap<>();
+
+ private final Config config;
+ private final CacheManager cacheManager;
+ private final Storage storage;
+ private final NotificationManager notificationManager;
+ private final Timer timer;
+ private final BroadcastService broadcastService;
+ private final DeviceLookupService deviceLookupService;
+
+ private final Map<Long, Set<UpdateListener>> listeners = new HashMap<>();
+ private final Map<Long, Set<Long>> userDevices = new HashMap<>();
+ private final Map<Long, Set<Long>> deviceUsers = new HashMap<>();
+
+ private final Map<Long, Timeout> timeouts = new ConcurrentHashMap<>();
+
+ @Inject
+ public ConnectionManager(
+ Config config, CacheManager cacheManager, Storage storage,
+ NotificationManager notificationManager, Timer timer, BroadcastService broadcastService,
+ DeviceLookupService deviceLookupService) {
+ this.config = config;
+ this.cacheManager = cacheManager;
+ this.storage = storage;
+ this.notificationManager = notificationManager;
+ this.timer = timer;
+ this.broadcastService = broadcastService;
+ this.deviceLookupService = deviceLookupService;
+ deviceTimeout = config.getLong(Keys.STATUS_TIMEOUT);
+ broadcastService.registerListener(this);
+ }
+
+ public DeviceSession getDeviceSession(long deviceId) {
+ return sessionsByDeviceId.get(deviceId);
+ }
+
+ public DeviceSession getDeviceSession(
+ Protocol protocol, Channel channel, SocketAddress remoteAddress,
+ String... uniqueIds) throws StorageException {
+
+ Endpoint endpoint = new Endpoint(channel, remoteAddress);
+ Map<String, DeviceSession> endpointSessions = sessionsByEndpoint.getOrDefault(
+ endpoint, new ConcurrentHashMap<>());
+
+ uniqueIds = Arrays.stream(uniqueIds).filter(Objects::nonNull).toArray(String[]::new);
+ if (uniqueIds.length > 0) {
+ for (String uniqueId : uniqueIds) {
+ DeviceSession deviceSession = endpointSessions.get(uniqueId);
+ if (deviceSession != null) {
+ return deviceSession;
+ }
+ }
+ } else {
+ return endpointSessions.values().stream().findAny().orElse(null);
+ }
+
+ Device device = deviceLookupService.lookup(uniqueIds);
+
+ if (device == null && config.getBoolean(Keys.DATABASE_REGISTER_UNKNOWN)) {
+ if (uniqueIds[0].matches(config.getString(Keys.DATABASE_REGISTER_UNKNOWN_REGEX))) {
+ device = addUnknownDevice(uniqueIds[0]);
+ }
+ }
+
+ if (device != null) {
+ device.checkDisabled();
+
+ DeviceSession oldSession = sessionsByDeviceId.remove(device.getId());
+ if (oldSession != null) {
+ Endpoint oldEndpoint = new Endpoint(oldSession.getChannel(), oldSession.getRemoteAddress());
+ Map<String, DeviceSession> oldEndpointSessions = sessionsByEndpoint.get(oldEndpoint);
+ if (oldEndpointSessions != null && oldEndpointSessions.size() > 1) {
+ oldEndpointSessions.remove(device.getUniqueId());
+ } else {
+ sessionsByEndpoint.remove(oldEndpoint);
+ }
+ }
+
+ DeviceSession deviceSession = new DeviceSession(
+ device.getId(), device.getUniqueId(), protocol, channel, remoteAddress);
+ endpointSessions.put(device.getUniqueId(), deviceSession);
+ sessionsByEndpoint.put(endpoint, endpointSessions);
+ sessionsByDeviceId.put(device.getId(), deviceSession);
+
+ if (oldSession == null) {
+ cacheManager.addDevice(device.getId());
+ }
+
+ return deviceSession;
+ } else {
+ LOGGER.warn("Unknown device - " + String.join(" ", uniqueIds)
+ + " (" + ((InetSocketAddress) remoteAddress).getHostString() + ")");
+ return null;
+ }
+ }
+
+ private Device addUnknownDevice(String uniqueId) {
+ Device device = new Device();
+ device.setName(uniqueId);
+ device.setUniqueId(uniqueId);
+ device.setCategory(config.getString(Keys.DATABASE_REGISTER_UNKNOWN_DEFAULT_CATEGORY));
+
+ long defaultGroupId = config.getLong(Keys.DATABASE_REGISTER_UNKNOWN_DEFAULT_GROUP_ID);
+ if (defaultGroupId != 0) {
+ device.setGroupId(defaultGroupId);
+ }
+
+ try {
+ device.setId(storage.addObject(device, new Request(new Columns.Exclude("id"))));
+ LOGGER.info("Automatically registered " + uniqueId);
+ return device;
+ } catch (StorageException e) {
+ LOGGER.warn("Automatic registration failed", e);
+ return null;
+ }
+ }
+
+ public void deviceDisconnected(Channel channel, boolean supportsOffline) {
+ Endpoint endpoint = new Endpoint(channel, channel.remoteAddress());
+ Map<String, DeviceSession> endpointSessions = sessionsByEndpoint.remove(endpoint);
+ if (endpointSessions != null) {
+ for (DeviceSession deviceSession : endpointSessions.values()) {
+ if (supportsOffline) {
+ updateDevice(deviceSession.getDeviceId(), Device.STATUS_OFFLINE, null);
+ }
+ sessionsByDeviceId.remove(deviceSession.getDeviceId());
+ cacheManager.removeDevice(deviceSession.getDeviceId());
+ }
+ }
+ }
+
+ public void deviceUnknown(long deviceId) {
+ updateDevice(deviceId, Device.STATUS_UNKNOWN, null);
+ removeDeviceSession(deviceId);
+ }
+
+ private void removeDeviceSession(long deviceId) {
+ DeviceSession deviceSession = sessionsByDeviceId.remove(deviceId);
+ if (deviceSession != null) {
+ cacheManager.removeDevice(deviceId);
+ Endpoint endpoint = new Endpoint(deviceSession.getChannel(), deviceSession.getRemoteAddress());
+ sessionsByEndpoint.computeIfPresent(endpoint, (e, sessions) -> {
+ sessions.remove(deviceSession.getUniqueId());
+ return sessions.isEmpty() ? null : sessions;
+ });
+ }
+ }
+
+ public void updateDevice(long deviceId, String status, Date time) {
+ Device device = cacheManager.getObject(Device.class, deviceId);
+ if (device == null) {
+ try {
+ device = storage.getObject(Device.class, new Request(
+ new Columns.All(), new Condition.Equals("id", deviceId)));
+ } catch (StorageException e) {
+ LOGGER.warn("Failed to get device", e);
+ }
+ if (device == null) {
+ return;
+ }
+ }
+
+ String oldStatus = device.getStatus();
+ device.setStatus(status);
+
+ if (!status.equals(oldStatus)) {
+ String eventType;
+ Map<Event, Position> events = new HashMap<>();
+ switch (status) {
+ case Device.STATUS_ONLINE:
+ eventType = Event.TYPE_DEVICE_ONLINE;
+ break;
+ case Device.STATUS_UNKNOWN:
+ eventType = Event.TYPE_DEVICE_UNKNOWN;
+ break;
+ default:
+ eventType = Event.TYPE_DEVICE_OFFLINE;
+ break;
+ }
+ events.put(new Event(eventType, deviceId), null);
+ notificationManager.updateEvents(events);
+ }
+
+ if (time != null) {
+ device.setLastUpdate(time);
+ }
+
+ Timeout timeout = timeouts.remove(deviceId);
+ if (timeout != null) {
+ timeout.cancel();
+ }
+
+ if (status.equals(Device.STATUS_ONLINE)) {
+ timeouts.put(deviceId, timer.newTimeout(timeout1 -> {
+ if (!timeout1.isCancelled()) {
+ deviceUnknown(deviceId);
+ }
+ }, deviceTimeout, TimeUnit.SECONDS));
+ }
+
+ try {
+ storage.updateObject(device, new Request(
+ new Columns.Include("status", "lastUpdate"),
+ new Condition.Equals("id", deviceId)));
+ } catch (StorageException e) {
+ LOGGER.warn("Update device status error", e);
+ }
+
+ updateDevice(true, device);
+ }
+
+ public synchronized void sendKeepalive() {
+ for (Set<UpdateListener> userListeners : listeners.values()) {
+ for (UpdateListener listener : userListeners) {
+ listener.onKeepalive();
+ }
+ }
+ }
+
+ @Override
+ public synchronized void updateDevice(boolean local, Device device) {
+ if (local) {
+ broadcastService.updateDevice(true, device);
+ } else if (Device.STATUS_ONLINE.equals(device.getStatus())) {
+ timeouts.remove(device.getId());
+ removeDeviceSession(device.getId());
+ }
+ for (long userId : deviceUsers.getOrDefault(device.getId(), Collections.emptySet())) {
+ if (listeners.containsKey(userId)) {
+ for (UpdateListener listener : listeners.get(userId)) {
+ listener.onUpdateDevice(device);
+ }
+ }
+ }
+ }
+
+ @Override
+ public synchronized void updatePosition(boolean local, Position position) {
+ if (local) {
+ broadcastService.updatePosition(true, position);
+ }
+ for (long userId : deviceUsers.getOrDefault(position.getDeviceId(), Collections.emptySet())) {
+ if (listeners.containsKey(userId)) {
+ for (UpdateListener listener : listeners.get(userId)) {
+ listener.onUpdatePosition(position);
+ }
+ }
+ }
+ }
+
+ @Override
+ public synchronized void updateEvent(boolean local, long userId, Event event) {
+ if (local) {
+ broadcastService.updateEvent(true, userId, event);
+ }
+ if (listeners.containsKey(userId)) {
+ for (UpdateListener listener : listeners.get(userId)) {
+ listener.onUpdateEvent(event);
+ }
+ }
+ }
+
+ @Override
+ public synchronized void invalidatePermission(
+ boolean local,
+ Class<? extends BaseModel> clazz1, long id1,
+ Class<? extends BaseModel> clazz2, long id2) {
+ if (clazz1.equals(User.class) && clazz2.equals(Device.class)) {
+ if (listeners.containsKey(id1)) {
+ userDevices.get(id1).add(id2);
+ deviceUsers.put(id2, new HashSet<>(List.of(id1)));
+ }
+ }
+ }
+
+ public interface UpdateListener {
+ void onKeepalive();
+ void onUpdateDevice(Device device);
+ void onUpdatePosition(Position position);
+ void onUpdateEvent(Event event);
+ }
+
+ public synchronized void addListener(long userId, UpdateListener listener) throws StorageException {
+ var set = listeners.get(userId);
+ if (set == null) {
+ set = new HashSet<>();
+ listeners.put(userId, set);
+
+ var devices = storage.getObjects(Device.class, new Request(
+ new Columns.Include("id"), new Condition.Permission(User.class, userId, Device.class)));
+ userDevices.put(userId, devices.stream().map(BaseModel::getId).collect(Collectors.toSet()));
+ devices.forEach(device -> deviceUsers.computeIfAbsent(device.getId(), id -> new HashSet<>()).add(userId));
+ }
+ set.add(listener);
+ }
+
+ public synchronized void removeListener(long userId, UpdateListener listener) {
+ var set = listeners.get(userId);
+ set.remove(listener);
+ if (set.isEmpty()) {
+ listeners.remove(userId);
+
+ userDevices.remove(userId).forEach(deviceId -> deviceUsers.computeIfPresent(deviceId, (x, userIds) -> {
+ userIds.remove(userId);
+ return userIds.isEmpty() ? null : userIds;
+ }));
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/database/ActiveDevice.java b/src/main/java/org/traccar/session/DeviceSession.java
index c05d56ad2..009f90f5a 100644
--- a/src/main/java/org/traccar/database/ActiveDevice.java
+++ b/src/main/java/org/traccar/session/DeviceSession.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.database;
+package org.traccar.session;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.HttpRequestDecoder;
@@ -22,37 +22,69 @@ import org.traccar.Protocol;
import org.traccar.model.Command;
import java.net.SocketAddress;
+import java.util.HashMap;
+import java.util.Map;
-public class ActiveDevice {
+public class DeviceSession {
private final long deviceId;
+ private final String uniqueId;
private final Protocol protocol;
private final Channel channel;
private final SocketAddress remoteAddress;
- private final boolean supportsLiveCommands;
- public ActiveDevice(long deviceId, Protocol protocol, Channel channel, SocketAddress remoteAddress) {
+ public DeviceSession(
+ long deviceId, String uniqueId, Protocol protocol, Channel channel, SocketAddress remoteAddress) {
this.deviceId = deviceId;
+ this.uniqueId = uniqueId;
this.protocol = protocol;
this.channel = channel;
this.remoteAddress = remoteAddress;
- supportsLiveCommands = BasePipelineFactory.getHandler(channel.pipeline(), HttpRequestDecoder.class) == null;
+ }
+
+ public long getDeviceId() {
+ return deviceId;
+ }
+
+ public String getUniqueId() {
+ return uniqueId;
}
public Channel getChannel() {
return channel;
}
- public long getDeviceId() {
- return deviceId;
+ public SocketAddress getRemoteAddress() {
+ return remoteAddress;
}
public boolean supportsLiveCommands() {
- return supportsLiveCommands;
+ return BasePipelineFactory.getHandler(channel.pipeline(), HttpRequestDecoder.class) == null;
}
public void sendCommand(Command command) {
protocol.sendDataCommand(channel, remoteAddress, command);
}
+ public static final String KEY_TIMEZONE = "timezone";
+
+ private final Map<String, Object> locals = new HashMap<>();
+
+ public boolean contains(String key) {
+ return locals.containsKey(key);
+ }
+
+ public void set(String key, Object value) {
+ if (value != null) {
+ locals.put(key, value);
+ } else {
+ locals.remove(key);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T get(String key) {
+ return (T) locals.get(key);
+ }
+
}
diff --git a/src/main/java/org/traccar/session/Endpoint.java b/src/main/java/org/traccar/session/Endpoint.java
new file mode 100644
index 000000000..76aac3444
--- /dev/null
+++ b/src/main/java/org/traccar/session/Endpoint.java
@@ -0,0 +1,58 @@
+/*
+ * 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.session;
+
+import io.netty.channel.Channel;
+
+import java.net.SocketAddress;
+import java.util.Objects;
+
+public class Endpoint {
+
+ private final Channel channel;
+ private final SocketAddress remoteAddress;
+
+ public Endpoint(Channel channel, SocketAddress remoteAddress) {
+ this.channel = channel;
+ this.remoteAddress = remoteAddress;
+ }
+
+ public Channel getChannel() {
+ return channel;
+ }
+
+ public SocketAddress getRemoteAddress() {
+ return remoteAddress;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Endpoint endpoint = (Endpoint) o;
+ return channel.equals(endpoint.channel) && remoteAddress.equals(endpoint.remoteAddress);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(channel, remoteAddress);
+ }
+
+}
diff --git a/src/main/java/org/traccar/session/cache/CacheKey.java b/src/main/java/org/traccar/session/cache/CacheKey.java
new file mode 100644
index 000000000..23145e34b
--- /dev/null
+++ b/src/main/java/org/traccar/session/cache/CacheKey.java
@@ -0,0 +1,57 @@
+/*
+ * 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.session.cache;
+
+import org.traccar.model.BaseModel;
+
+import java.util.Objects;
+
+class CacheKey {
+
+ private final Class<? extends BaseModel> clazz;
+ private final long id;
+
+ CacheKey(BaseModel object) {
+ this(object.getClass(), object.getId());
+ }
+
+ CacheKey(Class<? extends BaseModel> clazz, long id) {
+ this.clazz = clazz;
+ this.id = id;
+ }
+
+ public boolean classIs(Class<? extends BaseModel> clazz) {
+ return clazz.equals(this.clazz);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CacheKey cacheKey = (CacheKey) o;
+ return id == cacheKey.id && Objects.equals(clazz, cacheKey.clazz);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(clazz, id);
+ }
+
+}
diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java
new file mode 100644
index 000000000..58320cf29
--- /dev/null
+++ b/src/main/java/org/traccar/session/cache/CacheManager.java
@@ -0,0 +1,428 @@
+/*
+ * Copyright 2022 - 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.session.cache;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.broadcast.BroadcastInterface;
+import org.traccar.broadcast.BroadcastService;
+import org.traccar.config.Config;
+import org.traccar.model.Attribute;
+import org.traccar.model.BaseModel;
+import org.traccar.model.Calendar;
+import org.traccar.model.Device;
+import org.traccar.model.Driver;
+import org.traccar.model.Geofence;
+import org.traccar.model.Group;
+import org.traccar.model.GroupedModel;
+import org.traccar.model.Maintenance;
+import org.traccar.model.Notification;
+import org.traccar.model.Position;
+import org.traccar.model.Schedulable;
+import org.traccar.model.Server;
+import org.traccar.model.User;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.stream.Collectors;
+
+@Singleton
+public class CacheManager implements BroadcastInterface {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(CacheManager.class);
+ private static final int GROUP_DEPTH_LIMIT = 3;
+ private static final Collection<Class<? extends BaseModel>> CLASSES = Arrays.asList(
+ Attribute.class, Driver.class, Geofence.class, Maintenance.class, Notification.class);
+
+ private final Config config;
+ private final Storage storage;
+ private final BroadcastService broadcastService;
+
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+
+ private final Map<CacheKey, CacheValue> deviceCache = new HashMap<>();
+ private final Map<Long, Integer> deviceReferences = new HashMap<>();
+ private final Map<Long, Map<Class<? extends BaseModel>, Set<Long>>> deviceLinks = new HashMap<>();
+ private final Map<Long, Position> devicePositions = new HashMap<>();
+
+ private Server server;
+ private final Map<Long, List<User>> notificationUsers = new HashMap<>();
+
+ @Inject
+ public CacheManager(Config config, Storage storage, BroadcastService broadcastService) throws StorageException {
+ this.config = config;
+ this.storage = storage;
+ this.broadcastService = broadcastService;
+ invalidateServer();
+ invalidateUsers();
+ broadcastService.registerListener(this);
+ }
+
+ public Config getConfig() {
+ return config;
+ }
+
+ public <T extends BaseModel> T getObject(Class<T> clazz, long id) {
+ try {
+ lock.readLock().lock();
+ var cacheValue = deviceCache.get(new CacheKey(clazz, id));
+ return cacheValue != null ? cacheValue.getValue() : null;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ public <T extends BaseModel> List<T> getDeviceObjects(long deviceId, Class<T> clazz) {
+ try {
+ lock.readLock().lock();
+ var links = deviceLinks.get(deviceId);
+ if (links != null) {
+ return links.getOrDefault(clazz, new LinkedHashSet<>()).stream()
+ .map(id -> {
+ var cacheValue = deviceCache.get(new CacheKey(clazz, id));
+ return cacheValue != null ? cacheValue.<T>getValue() : null;
+ })
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ } else {
+ LOGGER.warn("Device {} cache missing", deviceId);
+ return Collections.emptyList();
+ }
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ public Position getPosition(long deviceId) {
+ try {
+ lock.readLock().lock();
+ return devicePositions.get(deviceId);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ public Server getServer() {
+ try {
+ lock.readLock().lock();
+ return server;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ public List<User> getNotificationUsers(long notificationId, long deviceId) {
+ try {
+ lock.readLock().lock();
+ var users = deviceLinks.get(deviceId).get(User.class).stream()
+ .collect(Collectors.toUnmodifiableSet());
+ return notificationUsers.getOrDefault(notificationId, new LinkedList<>()).stream()
+ .filter(user -> users.contains(user.getId()))
+ .collect(Collectors.toUnmodifiableList());
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ public Driver findDriverByUniqueId(long deviceId, String driverUniqueId) {
+ return getDeviceObjects(deviceId, Driver.class).stream()
+ .filter(driver -> driver.getUniqueId().equals(driverUniqueId))
+ .findFirst()
+ .orElse(null);
+ }
+
+ public void addDevice(long deviceId) throws StorageException {
+ try {
+ lock.writeLock().lock();
+ Integer references = deviceReferences.get(deviceId);
+ if (references != null) {
+ references += 1;
+ } else {
+ unsafeAddDevice(deviceId);
+ references = 1;
+ }
+ deviceReferences.put(deviceId, references);
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ public void removeDevice(long deviceId) {
+ try {
+ lock.writeLock().lock();
+ Integer references = deviceReferences.get(deviceId);
+ if (references != null) {
+ references -= 1;
+ if (references <= 0) {
+ unsafeRemoveDevice(deviceId);
+ deviceReferences.remove(deviceId);
+ } else {
+ deviceReferences.put(deviceId, references);
+ }
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ public void updatePosition(Position position) {
+ try {
+ lock.writeLock().lock();
+ if (deviceLinks.containsKey(position.getDeviceId())) {
+ devicePositions.put(position.getDeviceId(), position);
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public void invalidateObject(boolean local, Class<? extends BaseModel> clazz, long id) {
+ try {
+ var object = storage.getObject(clazz, new Request(
+ new Columns.All(), new Condition.Equals("id", id)));
+ if (object != null) {
+ updateOrInvalidate(local, object);
+ } else {
+ invalidate(clazz, id);
+ }
+ } catch (StorageException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public <T extends BaseModel> void updateOrInvalidate(boolean local, T object) throws StorageException {
+ if (local) {
+ broadcastService.invalidateObject(true, object.getClass(), object.getId());
+ }
+
+ if (object instanceof Server) {
+ invalidateServer();
+ return;
+ }
+ if (object instanceof User) {
+ invalidateUsers();
+ return;
+ }
+
+ boolean invalidate = false;
+ var before = getObject(object.getClass(), object.getId());
+ if (before == null) {
+ return;
+ } else if (object instanceof GroupedModel) {
+ if (((GroupedModel) before).getGroupId() != ((GroupedModel) object).getGroupId()) {
+ invalidate = true;
+ }
+ } else if (object instanceof Schedulable) {
+ if (((Schedulable) before).getCalendarId() != ((Schedulable) object).getCalendarId()) {
+ invalidate = true;
+ }
+ }
+ if (invalidate) {
+ invalidate(object.getClass(), object.getId());
+ } else {
+ try {
+ lock.writeLock().lock();
+ deviceCache.get(new CacheKey(object.getClass(), object.getId())).setValue(object);
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+ }
+
+ public <T extends BaseModel> void invalidate(Class<T> clazz, long id) throws StorageException {
+ invalidate(new CacheKey(clazz, id));
+ }
+
+ @Override
+ public void invalidatePermission(
+ boolean local,
+ Class<? extends BaseModel> clazz1, long id1,
+ Class<? extends BaseModel> clazz2, long id2) {
+ if (local) {
+ broadcastService.invalidatePermission(true, clazz1, id1, clazz2, id2);
+ }
+
+ try {
+ invalidate(new CacheKey(clazz1, id1), new CacheKey(clazz2, id2));
+ } catch (StorageException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void invalidateServer() throws StorageException {
+ server = storage.getObject(Server.class, new Request(new Columns.All()));
+ }
+
+ private void invalidateUsers() throws StorageException {
+ notificationUsers.clear();
+ Map<Long, User> users = new HashMap<>();
+ storage.getObjects(User.class, new Request(new Columns.All()))
+ .forEach(user -> users.put(user.getId(), user));
+ storage.getPermissions(User.class, Notification.class).forEach(permission -> {
+ long notificationId = permission.getPropertyId();
+ var user = users.get(permission.getOwnerId());
+ notificationUsers.computeIfAbsent(notificationId, k -> new LinkedList<>()).add(user);
+ });
+ }
+
+ private void addObject(long deviceId, BaseModel object) {
+ deviceCache.computeIfAbsent(new CacheKey(object), k -> new CacheValue(object)).retain(deviceId);
+ }
+
+ private void unsafeAddDevice(long deviceId) throws StorageException {
+ Map<Class<? extends BaseModel>, Set<Long>> links = new HashMap<>();
+
+ Device device = storage.getObject(Device.class, new Request(
+ new Columns.All(), new Condition.Equals("id", deviceId)));
+ if (device != null) {
+ addObject(deviceId, device);
+ if (device.getCalendarId() > 0) {
+ var calendar = storage.getObject(Calendar.class, new Request(
+ new Columns.All(), new Condition.Equals("id", device.getCalendarId())));
+ links.computeIfAbsent(Calendar.class, k -> new LinkedHashSet<>()).add(calendar.getId());
+ addObject(deviceId, calendar);
+ }
+
+ int groupDepth = 0;
+ long groupId = device.getGroupId();
+ while (groupDepth < GROUP_DEPTH_LIMIT && groupId > 0) {
+ Group group = storage.getObject(Group.class, new Request(
+ new Columns.All(), new Condition.Equals("id", groupId)));
+ links.computeIfAbsent(Group.class, k -> new LinkedHashSet<>()).add(group.getId());
+ addObject(deviceId, group);
+ groupId = group.getGroupId();
+ groupDepth += 1;
+ }
+
+ for (Class<? extends BaseModel> clazz : CLASSES) {
+ var objects = storage.getObjects(clazz, new Request(
+ new Columns.All(), new Condition.Permission(Device.class, deviceId, clazz)));
+ links.put(clazz, objects.stream().map(BaseModel::getId).collect(Collectors.toSet()));
+ for (var object : objects) {
+ addObject(deviceId, object);
+ if (object instanceof Schedulable) {
+ var scheduled = (Schedulable) object;
+ if (scheduled.getCalendarId() > 0) {
+ var calendar = storage.getObject(Calendar.class, new Request(
+ new Columns.All(), new Condition.Equals("id", scheduled.getCalendarId())));
+ links.computeIfAbsent(Calendar.class, k -> new LinkedHashSet<>()).add(calendar.getId());
+ addObject(deviceId, calendar);
+ }
+ }
+ }
+ }
+
+ var users = storage.getObjects(User.class, new Request(
+ new Columns.All(), new Condition.Permission(User.class, Device.class, deviceId)));
+ links.put(User.class, users.stream().map(BaseModel::getId).collect(Collectors.toSet()));
+ for (var user : users) {
+ addObject(deviceId, user);
+ var notifications = storage.getObjects(Notification.class, new Request(
+ new Columns.All(),
+ new Condition.Permission(User.class, user.getId(), Notification.class))).stream()
+ .filter(Notification::getAlways)
+ .collect(Collectors.toList());
+ for (var notification : notifications) {
+ links.computeIfAbsent(Notification.class, k -> new LinkedHashSet<>()).add(notification.getId());
+ addObject(deviceId, notification);
+ if (notification.getCalendarId() > 0) {
+ var calendar = storage.getObject(Calendar.class, new Request(
+ new Columns.All(), new Condition.Equals("id", notification.getCalendarId())));
+ links.computeIfAbsent(Calendar.class, k -> new LinkedHashSet<>()).add(calendar.getId());
+ addObject(deviceId, calendar);
+ }
+ }
+ }
+
+ deviceLinks.put(deviceId, links);
+
+ if (device.getPositionId() > 0) {
+ devicePositions.put(deviceId, storage.getObject(Position.class, new Request(
+ new Columns.All(), new Condition.Equals("id", device.getPositionId()))));
+ }
+ }
+ }
+
+ private void unsafeRemoveDevice(long deviceId) {
+ deviceCache.remove(new CacheKey(Device.class, deviceId));
+ deviceLinks.remove(deviceId).forEach((clazz, ids) -> ids.forEach(id -> {
+ var key = new CacheKey(clazz, id);
+ deviceCache.computeIfPresent(key, (k, value) -> {
+ value.release(deviceId);
+ return value.getReferences().size() > 0 ? value : null;
+ });
+ }));
+ devicePositions.remove(deviceId);
+ }
+
+ private void invalidate(CacheKey... keys) throws StorageException {
+ try {
+ lock.writeLock().lock();
+ unsafeInvalidate(keys);
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ private void unsafeInvalidate(CacheKey[] keys) throws StorageException {
+ boolean invalidateServer = false;
+ boolean invalidateUsers = false;
+ Set<Long> linkedDevices = new HashSet<>();
+ for (var key : keys) {
+ if (key.classIs(Server.class)) {
+ invalidateServer = true;
+ } else {
+ if (key.classIs(User.class) || key.classIs(Notification.class)) {
+ invalidateUsers = true;
+ }
+ deviceCache.computeIfPresent(key, (k, value) -> {
+ linkedDevices.addAll(value.getReferences());
+ return value;
+ });
+ }
+ }
+ for (long deviceId : linkedDevices) {
+ unsafeRemoveDevice(deviceId);
+ unsafeAddDevice(deviceId);
+ }
+ if (invalidateServer) {
+ invalidateServer();
+ }
+ if (invalidateUsers) {
+ invalidateUsers();
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/session/cache/CacheValue.java b/src/main/java/org/traccar/session/cache/CacheValue.java
new file mode 100644
index 000000000..1f0383ce5
--- /dev/null
+++ b/src/main/java/org/traccar/session/cache/CacheValue.java
@@ -0,0 +1,53 @@
+/*
+ * 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.session.cache;
+
+import org.traccar.model.BaseModel;
+
+import java.util.HashSet;
+import java.util.Set;
+
+class CacheValue {
+
+ private BaseModel value;
+ private final Set<Long> references = new HashSet<>();
+
+ CacheValue(BaseModel value) {
+ this.value = value;
+ }
+
+ public void retain(long deviceId) {
+ references.add(deviceId);
+ }
+
+ public void release(long deviceId) {
+ references.remove(deviceId);
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T extends BaseModel> T getValue() {
+ return (T) value;
+ }
+
+ public void setValue(BaseModel value) {
+ this.value = value;
+ }
+
+ public Set<Long> getReferences() {
+ return references;
+ }
+
+}
diff --git a/src/main/java/org/traccar/session/state/MotionProcessor.java b/src/main/java/org/traccar/session/state/MotionProcessor.java
new file mode 100644
index 000000000..a1737a739
--- /dev/null
+++ b/src/main/java/org/traccar/session/state/MotionProcessor.java
@@ -0,0 +1,81 @@
+/*
+ * 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.session.state;
+
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+import org.traccar.reports.common.TripsConfig;
+
+public final class MotionProcessor {
+
+ private MotionProcessor() {
+ }
+
+ public static void updateState(
+ MotionState state, Position position, boolean newState, TripsConfig tripsConfig) {
+
+ state.setEvent(null);
+
+ boolean oldState = state.getMotionState();
+ if (oldState == newState) {
+ if (state.getMotionTime() != null) {
+ long oldTime = state.getMotionTime().getTime();
+ long newTime = position.getFixTime().getTime();
+
+ double distance = position.getDouble(Position.KEY_TOTAL_DISTANCE) - state.getMotionDistance();
+ Boolean ignition = null;
+ if (tripsConfig.getUseIgnition() && position.hasAttribute(Position.KEY_IGNITION)) {
+ ignition = position.getBoolean(Position.KEY_IGNITION);
+ }
+
+ boolean generateEvent = false;
+ if (newState) {
+ if (newTime - oldTime >= tripsConfig.getMinimalTripDuration()
+ || distance >= tripsConfig.getMinimalTripDistance()) {
+ generateEvent = true;
+ }
+ } else {
+ if (newTime - oldTime >= tripsConfig.getMinimalParkingDuration()
+ || ignition != null && !ignition) {
+ generateEvent = true;
+ }
+ }
+
+ if (generateEvent) {
+
+ String eventType = newState ? Event.TYPE_DEVICE_MOVING : Event.TYPE_DEVICE_STOPPED;
+ Event event = new Event(eventType, position);
+
+ state.setMotionStreak(newState);
+ state.setMotionTime(null);
+ state.setMotionDistance(0);
+ state.setEvent(event);
+
+ }
+ }
+ } else {
+ state.setMotionState(newState);
+ if (state.getMotionStreak() == newState) {
+ state.setMotionTime(null);
+ state.setMotionDistance(0);
+ } else {
+ state.setMotionTime(position.getFixTime());
+ state.setMotionDistance(position.getDouble(Position.KEY_TOTAL_DISTANCE));
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/session/state/MotionState.java b/src/main/java/org/traccar/session/state/MotionState.java
new file mode 100644
index 000000000..6c917ad16
--- /dev/null
+++ b/src/main/java/org/traccar/session/state/MotionState.java
@@ -0,0 +1,101 @@
+/*
+ * 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.session.state;
+
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+
+import java.util.Date;
+
+public class MotionState {
+
+ public static MotionState fromDevice(Device device) {
+ MotionState state = new MotionState();
+ state.motionStreak = device.getMotionStreak();
+ state.motionState = device.getMotionState();
+ state.motionTime = device.getMotionTime();
+ state.motionDistance = device.getMotionDistance();
+ return state;
+ }
+
+ public void toDevice(Device device) {
+ device.setMotionStreak(motionStreak);
+ device.setMotionState(motionState);
+ device.setMotionTime(motionTime);
+ device.setMotionDistance(motionDistance);
+ }
+
+ private boolean changed;
+
+ public boolean isChanged() {
+ return changed;
+ }
+
+ private boolean motionStreak;
+
+ public boolean getMotionStreak() {
+ return motionStreak;
+ }
+
+ public void setMotionStreak(boolean motionStreak) {
+ this.motionStreak = motionStreak;
+ changed = true;
+ }
+
+ private boolean motionState;
+
+ public boolean getMotionState() {
+ return motionState;
+ }
+
+ public void setMotionState(boolean motionState) {
+ this.motionState = motionState;
+ changed = true;
+ }
+
+ private Date motionTime;
+
+ public Date getMotionTime() {
+ return motionTime;
+ }
+
+ public void setMotionTime(Date motionTime) {
+ this.motionTime = motionTime;
+ changed = true;
+ }
+
+ private double motionDistance;
+
+ public double getMotionDistance() {
+ return motionDistance;
+ }
+
+ public void setMotionDistance(double motionDistance) {
+ this.motionDistance = motionDistance;
+ changed = true;
+ }
+
+ private Event event;
+
+ public Event getEvent() {
+ return event;
+ }
+
+ public void setEvent(Event event) {
+ this.event = event;
+ }
+
+}
diff --git a/src/main/java/org/traccar/session/state/OverspeedProcessor.java b/src/main/java/org/traccar/session/state/OverspeedProcessor.java
new file mode 100644
index 000000000..221b51ff5
--- /dev/null
+++ b/src/main/java/org/traccar/session/state/OverspeedProcessor.java
@@ -0,0 +1,71 @@
+/*
+ * 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.session.state;
+
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+public final class OverspeedProcessor {
+
+ public static final String ATTRIBUTE_SPEED = "speed";
+
+ private OverspeedProcessor() {
+ }
+
+ public static void updateState(
+ OverspeedState state, Position position,
+ double speedLimit, double multiplier, long minimalDuration, long geofenceId) {
+
+ state.setEvent(null);
+
+ boolean oldState = state.getOverspeedState();
+ if (oldState) {
+ boolean newState = position.getSpeed() > speedLimit * multiplier;
+ if (newState) {
+ checkEvent(state, position, speedLimit, minimalDuration);
+ } else {
+ state.setOverspeedState(false);
+ state.setOverspeedTime(null);
+ state.setOverspeedGeofenceId(0);
+ }
+ } else if (position != null && position.getSpeed() > speedLimit * multiplier) {
+ state.setOverspeedState(true);
+ state.setOverspeedTime(position.getFixTime());
+ state.setOverspeedGeofenceId(geofenceId);
+
+ checkEvent(state, position, speedLimit, minimalDuration);
+ }
+ }
+
+ private static void checkEvent(OverspeedState state, Position position, double speedLimit, long minimalDuration) {
+ if (state.getOverspeedTime() != null) {
+ long oldTime = state.getOverspeedTime().getTime();
+ long newTime = position.getFixTime().getTime();
+ if (newTime - oldTime >= minimalDuration) {
+
+ Event event = new Event(Event.TYPE_DEVICE_OVERSPEED, position);
+ event.set(ATTRIBUTE_SPEED, position.getSpeed());
+ event.set(Position.KEY_SPEED_LIMIT, speedLimit);
+ event.setGeofenceId(state.getOverspeedGeofenceId());
+
+ state.setOverspeedTime(null);
+ state.setOverspeedGeofenceId(0);
+ state.setEvent(event);
+
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/traccar/session/state/OverspeedState.java b/src/main/java/org/traccar/session/state/OverspeedState.java
new file mode 100644
index 000000000..340ede6d7
--- /dev/null
+++ b/src/main/java/org/traccar/session/state/OverspeedState.java
@@ -0,0 +1,88 @@
+/*
+ * 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.session.state;
+
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+
+import java.util.Date;
+
+public class OverspeedState {
+
+ public static OverspeedState fromDevice(Device device) {
+ OverspeedState state = new OverspeedState();
+ state.overspeedState = device.getOverspeedState();
+ state.overspeedTime = device.getOverspeedTime();
+ state.overspeedGeofenceId = device.getOverspeedGeofenceId();
+ return state;
+ }
+
+ public void toDevice(Device device) {
+ device.setOverspeedState(overspeedState);
+ device.setOverspeedTime(overspeedTime);
+ device.setOverspeedGeofenceId(overspeedGeofenceId);
+ }
+
+ private boolean changed;
+
+ public boolean isChanged() {
+ return changed;
+ }
+
+ private boolean overspeedState;
+
+ public boolean getOverspeedState() {
+ return overspeedState;
+ }
+
+ public void setOverspeedState(boolean overspeedState) {
+ this.overspeedState = overspeedState;
+ changed = true;
+ }
+
+ private Date overspeedTime;
+
+ public Date getOverspeedTime() {
+ return overspeedTime;
+ }
+
+ public void setOverspeedTime(Date overspeedTime) {
+ this.overspeedTime = overspeedTime;
+ changed = true;
+ }
+
+ private long overspeedGeofenceId;
+
+ public long getOverspeedGeofenceId() {
+ return overspeedGeofenceId;
+ }
+
+ public void setOverspeedGeofenceId(long overspeedGeofenceId) {
+ this.overspeedGeofenceId = overspeedGeofenceId;
+ changed = true;
+ }
+
+ private Event event;
+
+ public Event getEvent() {
+ return event;
+ }
+
+ public void setEvent(Event event) {
+ this.event = event;
+ }
+
+}
diff --git a/src/main/java/org/traccar/sms/HttpSmsClient.java b/src/main/java/org/traccar/sms/HttpSmsClient.java
index 6234eabb8..a2a0dd57f 100644
--- a/src/main/java/org/traccar/sms/HttpSmsClient.java
+++ b/src/main/java/org/traccar/sms/HttpSmsClient.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,26 +16,23 @@
*/
package org.traccar.sms;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.helper.DataConverter;
import org.traccar.notification.MessageException;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.Invocation;
-import javax.ws.rs.client.InvocationCallback;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.client.Invocation;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
public class HttpSmsClient implements SmsManager {
- private static final Logger LOGGER = LoggerFactory.getLogger(HttpSmsClient.class);
-
+ private final Client client;
private final String url;
private final String authorizationHeader;
private final String authorization;
@@ -43,14 +40,15 @@ public class HttpSmsClient implements SmsManager {
private final boolean encode;
private final MediaType mediaType;
- public HttpSmsClient() {
- url = Context.getConfig().getString(Keys.SMS_HTTP_URL);
- authorizationHeader = Context.getConfig().getString(Keys.SMS_HTTP_AUTHORIZATION_HEADER);
- if (Context.getConfig().hasKey(Keys.SMS_HTTP_AUTHORIZATION)) {
- authorization = Context.getConfig().getString(Keys.SMS_HTTP_AUTHORIZATION);
+ public HttpSmsClient(Config config, Client client) {
+ this.client = client;
+ url = config.getString(Keys.SMS_HTTP_URL);
+ authorizationHeader = config.getString(Keys.SMS_HTTP_AUTHORIZATION_HEADER);
+ if (config.hasKey(Keys.SMS_HTTP_AUTHORIZATION)) {
+ authorization = config.getString(Keys.SMS_HTTP_AUTHORIZATION);
} else {
- String user = Context.getConfig().getString(Keys.SMS_HTTP_USER);
- String password = Context.getConfig().getString(Keys.SMS_HTTP_PASSWORD);
+ String user = config.getString(Keys.SMS_HTTP_USER);
+ String password = config.getString(Keys.SMS_HTTP_PASSWORD);
if (user != null && password != null) {
authorization = "Basic "
+ DataConverter.printBase64((user + ":" + password).getBytes(StandardCharsets.UTF_8));
@@ -58,8 +56,11 @@ public class HttpSmsClient implements SmsManager {
authorization = null;
}
}
- template = Context.getConfig().getString(Keys.SMS_HTTP_TEMPLATE).trim();
- if (template.charAt(0) == '{' || template.charAt(0) == '[') {
+ template = config.getString(Keys.SMS_HTTP_TEMPLATE).trim();
+ if (template.charAt(0) == '<') {
+ encode = false;
+ mediaType = MediaType.APPLICATION_XML_TYPE;
+ } else if (template.charAt(0) == '{' || template.charAt(0) == '[') {
encode = false;
mediaType = MediaType.APPLICATION_JSON_TYPE;
} else {
@@ -69,7 +70,7 @@ public class HttpSmsClient implements SmsManager {
}
private String prepareValue(String value) throws UnsupportedEncodingException {
- return encode ? URLEncoder.encode(value, StandardCharsets.UTF_8.name()) : value;
+ return encode ? URLEncoder.encode(value, StandardCharsets.UTF_8) : value;
}
private String preparePayload(String destAddress, String message) {
@@ -83,7 +84,7 @@ public class HttpSmsClient implements SmsManager {
}
private Invocation.Builder getRequestBuilder() {
- Invocation.Builder builder = Context.getClient().target(url).request();
+ Invocation.Builder builder = client.target(url).request();
if (authorization != null) {
builder = builder.header(authorizationHeader, authorization);
}
@@ -91,26 +92,13 @@ public class HttpSmsClient implements SmsManager {
}
@Override
- public void sendMessageSync(String destAddress, String message, boolean command) throws MessageException {
- Response response = getRequestBuilder().post(Entity.entity(preparePayload(destAddress, message), mediaType));
- if (response.getStatus() / 100 != 2) {
- throw new MessageException(response.readEntity(String.class));
- }
- }
-
- @Override
- public void sendMessageAsync(final String destAddress, final String message, final boolean command) {
- getRequestBuilder().async().post(
- Entity.entity(preparePayload(destAddress, message), mediaType), new InvocationCallback<String>() {
- @Override
- public void completed(String s) {
- }
-
- @Override
- public void failed(Throwable throwable) {
- LOGGER.warn("SMS send failed", throwable);
+ public void sendMessage(String destAddress, String message, boolean command) throws MessageException {
+ try (Response response = getRequestBuilder()
+ .post(Entity.entity(preparePayload(destAddress, message), mediaType))) {
+ if (response.getStatus() / 100 != 2) {
+ throw new MessageException(response.readEntity(String.class));
}
- });
+ }
}
}
diff --git a/src/main/java/org/traccar/sms/SmsManager.java b/src/main/java/org/traccar/sms/SmsManager.java
index 3b0cbda7f..8cf99c9e8 100644
--- a/src/main/java/org/traccar/sms/SmsManager.java
+++ b/src/main/java/org/traccar/sms/SmsManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,10 +20,6 @@ import org.traccar.notification.MessageException;
public interface SmsManager {
- void sendMessageSync(
- String destAddress, String message, boolean command) throws InterruptedException, MessageException;
-
- void sendMessageAsync(
- String destAddress, String message, boolean command);
+ void sendMessage(String destAddress, String message, boolean command) throws MessageException;
}
diff --git a/src/main/java/org/traccar/sms/SnsSmsClient.java b/src/main/java/org/traccar/sms/SnsSmsClient.java
index bdd4104f5..ed5a325cc 100644
--- a/src/main/java/org/traccar/sms/SnsSmsClient.java
+++ b/src/main/java/org/traccar/sms/SnsSmsClient.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2021 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2021 Subodh Ranadive (subodhranadive3103@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,7 +27,7 @@ import com.amazonaws.services.sns.model.PublishRequest;
import com.amazonaws.services.sns.model.PublishResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.Context;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import java.util.HashMap;
@@ -38,23 +38,16 @@ public class SnsSmsClient implements SmsManager {
private final AmazonSNSAsync snsClient;
- public SnsSmsClient() {
- if (Context.getConfig().hasKey(Keys.SMS_AWS_REGION)
- && Context.getConfig().hasKey(Keys.SMS_AWS_ACCESS)
- && Context.getConfig().hasKey(Keys.SMS_AWS_SECRET)) {
- BasicAWSCredentials awsCredentials =
- new BasicAWSCredentials(Context.getConfig().getString(Keys.SMS_AWS_ACCESS),
- Context.getConfig().getString(Keys.SMS_AWS_SECRET));
- snsClient = AmazonSNSAsyncClientBuilder.standard()
- .withRegion(Context.getConfig().getString(Keys.SMS_AWS_REGION))
- .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)).build();
- } else {
- throw new RuntimeException("SNS Not Configured Properly. Please provide valid config.");
- }
+ public SnsSmsClient(Config config) {
+ BasicAWSCredentials awsCredentials = new BasicAWSCredentials(
+ config.getString(Keys.SMS_AWS_ACCESS), config.getString(Keys.SMS_AWS_SECRET));
+ snsClient = AmazonSNSAsyncClientBuilder.standard()
+ .withRegion(config.getString(Keys.SMS_AWS_REGION))
+ .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)).build();
}
@Override
- public void sendMessageSync(String destAddress, String message, boolean command) {
+ public void sendMessage(String destAddress, String message, boolean command) {
Map<String, MessageAttributeValue> smsAttributes = new HashMap<>();
smsAttributes.put("AWS.SNS.SMS.SenderID",
new MessageAttributeValue().withStringValue("SNS").withDataType("String"));
@@ -64,19 +57,15 @@ public class SnsSmsClient implements SmsManager {
PublishRequest publishRequest = new PublishRequest().withMessage(message)
.withPhoneNumber(destAddress).withMessageAttributes(smsAttributes);
- snsClient.publishAsync(publishRequest, new AsyncHandler<PublishRequest, PublishResult>() {
+ snsClient.publishAsync(publishRequest, new AsyncHandler<>() {
@Override
public void onError(Exception exception) {
LOGGER.error("SMS send failed", exception);
}
+
@Override
public void onSuccess(PublishRequest request, PublishResult result) {
}
});
}
-
- @Override
- public void sendMessageAsync(String destAddress, String message, boolean command) {
- sendMessageSync(destAddress, message, command);
- }
}
diff --git a/src/main/java/org/traccar/speedlimit/OverpassSpeedLimitProvider.java b/src/main/java/org/traccar/speedlimit/OverpassSpeedLimitProvider.java
index 429a47c76..60ad65f9e 100644
--- a/src/main/java/org/traccar/speedlimit/OverpassSpeedLimitProvider.java
+++ b/src/main/java/org/traccar/speedlimit/OverpassSpeedLimitProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2020 - 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,19 +15,21 @@
*/
package org.traccar.speedlimit;
-import org.traccar.Context;
import org.traccar.helper.UnitsConverter;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
-import javax.ws.rs.client.AsyncInvoker;
-import javax.ws.rs.client.InvocationCallback;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.ws.rs.client.AsyncInvoker;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.InvocationCallback;
public class OverpassSpeedLimitProvider implements SpeedLimitProvider {
+ private final Client client;
private final String url;
- public OverpassSpeedLimitProvider(String url) {
+ public OverpassSpeedLimitProvider(Client client, String url) {
+ this.client = client;
this.url = url + "?data=[out:json];way[maxspeed](around:100.0,%f,%f);out%%20tags;";
}
@@ -46,7 +48,7 @@ public class OverpassSpeedLimitProvider implements SpeedLimitProvider {
@Override
public void getSpeedLimit(double latitude, double longitude, SpeedLimitProviderCallback callback) {
String formattedUrl = String.format(url, latitude, longitude);
- AsyncInvoker invoker = Context.getClient().target(formattedUrl).request().async();
+ AsyncInvoker invoker = client.target(formattedUrl).request().async();
invoker.get(new InvocationCallback<JsonObject>() {
@Override
public void completed(JsonObject json) {
diff --git a/src/main/java/org/traccar/storage/DatabaseModule.java b/src/main/java/org/traccar/storage/DatabaseModule.java
new file mode 100644
index 000000000..9d9e5bd5e
--- /dev/null
+++ b/src/main/java/org/traccar/storage/DatabaseModule.java
@@ -0,0 +1,103 @@
+/*
+ * 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.storage;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+import liquibase.Contexts;
+import liquibase.Liquibase;
+import liquibase.database.Database;
+import liquibase.database.DatabaseFactory;
+import liquibase.exception.LiquibaseException;
+import liquibase.resource.DirectoryResourceAccessor;
+import liquibase.resource.ResourceAccessor;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import jakarta.inject.Singleton;
+import javax.sql.DataSource;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.net.URL;
+
+public class DatabaseModule extends AbstractModule {
+
+ @Singleton
+ @Provides
+ public static DataSource provideDataSource(
+ Config config) throws ReflectiveOperationException, IOException, LiquibaseException {
+
+ String driverFile = config.getString(Keys.DATABASE_DRIVER_FILE);
+ if (driverFile != null) {
+ ClassLoader classLoader = ClassLoader.getSystemClassLoader();
+ try {
+ Method method = classLoader.getClass().getDeclaredMethod("addURL", URL.class);
+ method.setAccessible(true);
+ method.invoke(classLoader, new File(driverFile).toURI().toURL());
+ } catch (NoSuchMethodException e) {
+ Method method = classLoader.getClass()
+ .getDeclaredMethod("appendToClassPathForInstrumentation", String.class);
+ method.setAccessible(true);
+ method.invoke(classLoader, driverFile);
+ }
+ }
+
+ String driver = config.getString(Keys.DATABASE_DRIVER);
+ if (driver != null) {
+ Class.forName(driver);
+ }
+
+ HikariConfig hikariConfig = new HikariConfig();
+ hikariConfig.setDriverClassName(driver);
+ hikariConfig.setJdbcUrl(config.getString(Keys.DATABASE_URL));
+ hikariConfig.setUsername(config.getString(Keys.DATABASE_USER));
+ hikariConfig.setPassword(config.getString(Keys.DATABASE_PASSWORD));
+ hikariConfig.setConnectionInitSql(config.getString(Keys.DATABASE_CHECK_CONNECTION));
+ hikariConfig.setIdleTimeout(600000);
+
+ int maxPoolSize = config.getInteger(Keys.DATABASE_MAX_POOL_SIZE);
+ if (maxPoolSize != 0) {
+ hikariConfig.setMaximumPoolSize(maxPoolSize);
+ }
+
+ DataSource dataSource = new HikariDataSource(hikariConfig);
+
+ if (config.hasKey(Keys.DATABASE_CHANGELOG)) {
+
+ ResourceAccessor resourceAccessor = new DirectoryResourceAccessor(new File("."));
+
+ Database database = DatabaseFactory.getInstance().openDatabase(
+ config.getString(Keys.DATABASE_URL),
+ config.getString(Keys.DATABASE_USER),
+ config.getString(Keys.DATABASE_PASSWORD),
+ config.getString(Keys.DATABASE_DRIVER),
+ null, null, null, resourceAccessor);
+
+ String changelog = config.getString(Keys.DATABASE_CHANGELOG);
+
+ try (Liquibase liquibase = new Liquibase(changelog, resourceAccessor, database)) {
+ liquibase.clearCheckSums();
+ liquibase.update(new Contexts());
+ }
+ }
+
+ return dataSource;
+ }
+
+}
diff --git a/src/main/java/org/traccar/storage/DatabaseStorage.java b/src/main/java/org/traccar/storage/DatabaseStorage.java
index d73dc7b25..d20429319 100644
--- a/src/main/java/org/traccar/storage/DatabaseStorage.java
+++ b/src/main/java/org/traccar/storage/DatabaseStorage.java
@@ -1,15 +1,37 @@
+/*
+ * 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.storage;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.traccar.config.Config;
+import org.traccar.model.BaseModel;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.model.GroupedModel;
import org.traccar.model.Permission;
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 jakarta.inject.Inject;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@@ -17,22 +39,37 @@ import java.util.stream.Collectors;
public class DatabaseStorage extends Storage {
+ private final Config config;
private final DataSource dataSource;
+ private final ObjectMapper objectMapper;
+ private final String databaseType;
- public DatabaseStorage(DataSource dataSource) {
+ @Inject
+ public DatabaseStorage(Config config, DataSource dataSource, ObjectMapper objectMapper) {
+ this.config = config;
this.dataSource = dataSource;
+ this.objectMapper = objectMapper;
+
+ try {
+ databaseType = dataSource.getConnection().getMetaData().getDatabaseProductName();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
}
@Override
public <T> List<T> getObjects(Class<T> clazz, Request request) throws StorageException {
StringBuilder query = new StringBuilder("SELECT ");
- query.append(formatColumns(request.getColumns(), clazz, "get", c -> c));
- query.append(" FROM ").append(getTableName(clazz));
+ if (request.getColumns() instanceof Columns.All) {
+ query.append('*');
+ } else {
+ query.append(formatColumns(request.getColumns().getColumns(clazz, "set"), c -> c));
+ }
+ query.append(" FROM ").append(getStorageName(clazz));
query.append(formatCondition(request.getCondition()));
query.append(formatOrder(request.getOrder()));
- query.append(formatLimit(request.getLimit()));
try {
- QueryBuilder builder = QueryBuilder.create(dataSource, query.toString());
+ QueryBuilder builder = QueryBuilder.create(config, dataSource, objectMapper, query.toString());
for (Map.Entry<String, Object> variable : getConditionVariables(request.getCondition()).entrySet()) {
builder.setValue(variable.getKey(), variable.getValue());
}
@@ -44,16 +81,17 @@ public class DatabaseStorage extends Storage {
@Override
public <T> long addObject(T entity, Request request) throws StorageException {
+ List<String> columns = request.getColumns().getColumns(entity.getClass(), "get");
StringBuilder query = new StringBuilder("INSERT INTO ");
- query.append(getTableName(entity.getClass()));
+ query.append(getStorageName(entity.getClass()));
query.append("(");
- query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> c));
+ query.append(formatColumns(columns, c -> c));
query.append(") VALUES (");
- query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> ':' + c));
+ query.append(formatColumns(columns, c -> ':' + c));
query.append(")");
try {
- QueryBuilder builder = QueryBuilder.create(dataSource, query.toString(), true);
- builder.setObject(entity);
+ QueryBuilder builder = QueryBuilder.create(config, dataSource, objectMapper, query.toString(), true);
+ builder.setObject(entity, columns);
return builder.executeUpdate();
} catch (SQLException e) {
throw new StorageException(e);
@@ -62,14 +100,15 @@ public class DatabaseStorage extends Storage {
@Override
public <T> void updateObject(T entity, Request request) throws StorageException {
+ List<String> columns = request.getColumns().getColumns(entity.getClass(), "get");
StringBuilder query = new StringBuilder("UPDATE ");
- query.append(getTableName(entity.getClass()));
+ query.append(getStorageName(entity.getClass()));
query.append(" SET ");
- query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> c + " = :" + c));
+ query.append(formatColumns(columns, c -> c + " = :" + c));
query.append(formatCondition(request.getCondition()));
try {
- QueryBuilder builder = QueryBuilder.create(dataSource, query.toString());
- builder.setObject(entity);
+ QueryBuilder builder = QueryBuilder.create(config, dataSource, objectMapper, query.toString());
+ builder.setObject(entity, columns);
for (Map.Entry<String, Object> variable : getConditionVariables(request.getCondition()).entrySet()) {
builder.setValue(variable.getKey(), variable.getValue());
}
@@ -82,10 +121,10 @@ public class DatabaseStorage extends Storage {
@Override
public void removeObject(Class<?> clazz, Request request) throws StorageException {
StringBuilder query = new StringBuilder("DELETE FROM ");
- query.append(getTableName(clazz));
+ query.append(getStorageName(clazz));
query.append(formatCondition(request.getCondition()));
try {
- QueryBuilder builder = QueryBuilder.create(dataSource, query.toString());
+ QueryBuilder builder = QueryBuilder.create(config, dataSource, objectMapper, query.toString());
for (Map.Entry<String, Object> variable : getConditionVariables(request.getCondition()).entrySet()) {
builder.setValue(variable.getKey(), variable.getValue());
}
@@ -96,11 +135,25 @@ public class DatabaseStorage extends Storage {
}
@Override
- public List<Permission> getPermissions(Class<?> ownerClass, Class<?> propertyClass) throws StorageException {
+ public List<Permission> getPermissions(
+ Class<? extends BaseModel> ownerClass, long ownerId,
+ Class<? extends BaseModel> propertyClass, long propertyId) throws StorageException {
StringBuilder query = new StringBuilder("SELECT * FROM ");
query.append(Permission.getStorageName(ownerClass, propertyClass));
+ var conditions = new LinkedList<Condition>();
+ if (ownerId > 0) {
+ conditions.add(new Condition.Equals(Permission.getKey(ownerClass), ownerId));
+ }
+ if (propertyId > 0) {
+ conditions.add(new Condition.Equals(Permission.getKey(propertyClass), propertyId));
+ }
+ Condition combinedCondition = Condition.merge(conditions);
+ query.append(formatCondition(combinedCondition));
try {
- QueryBuilder builder = QueryBuilder.create(dataSource, query.toString());
+ QueryBuilder builder = QueryBuilder.create(config, dataSource, objectMapper, query.toString());
+ for (Map.Entry<String, Object> variable : getConditionVariables(combinedCondition).entrySet()) {
+ builder.setValue(variable.getKey(), variable.getValue());
+ }
return builder.executePermissionsQuery();
} catch (SQLException e) {
throw new StorageException(e);
@@ -115,7 +168,7 @@ public class DatabaseStorage extends Storage {
query.append(permission.get().keySet().stream().map(key -> ':' + key).collect(Collectors.joining(", ")));
query.append(")");
try {
- QueryBuilder builder = QueryBuilder.create(dataSource, query.toString(), true);
+ QueryBuilder builder = QueryBuilder.create(config, dataSource, objectMapper, query.toString(), true);
for (var entry : permission.get().entrySet()) {
builder.setLong(entry.getKey(), entry.getValue());
}
@@ -133,7 +186,7 @@ public class DatabaseStorage extends Storage {
query.append(permission
.get().keySet().stream().map(key -> key + " = :" + key).collect(Collectors.joining(" AND ")));
try {
- QueryBuilder builder = QueryBuilder.create(dataSource, query.toString(), true);
+ QueryBuilder builder = QueryBuilder.create(config, dataSource, objectMapper, query.toString(), true);
for (var entry : permission.get().entrySet()) {
builder.setLong(entry.getKey(), entry.getValue());
}
@@ -143,7 +196,7 @@ public class DatabaseStorage extends Storage {
}
}
- private String getTableName(Class<?> clazz) throws StorageException {
+ private String getStorageName(Class<?> clazz) throws StorageException {
StorageName storageName = clazz.getAnnotation(StorageName.class);
if (storageName == null) {
throw new StorageException("StorageName annotation is missing");
@@ -154,32 +207,43 @@ public class DatabaseStorage extends Storage {
private Map<String, Object> getConditionVariables(Condition genericCondition) {
Map<String, Object> results = new HashMap<>();
if (genericCondition instanceof Condition.Compare) {
- Condition.Compare condition = (Condition.Compare) genericCondition;
+ var condition = (Condition.Compare) genericCondition;
if (condition.getValue() != null) {
results.put(condition.getVariable(), condition.getValue());
}
} else if (genericCondition instanceof Condition.Between) {
- Condition.Between condition = (Condition.Between) genericCondition;
+ var condition = (Condition.Between) genericCondition;
results.put(condition.getFromVariable(), condition.getFromValue());
results.put(condition.getToVariable(), condition.getToValue());
} else if (genericCondition instanceof Condition.Binary) {
- Condition.Binary condition = (Condition.Binary) genericCondition;
+ var condition = (Condition.Binary) genericCondition;
results.putAll(getConditionVariables(condition.getFirst()));
results.putAll(getConditionVariables(condition.getSecond()));
+ } else if (genericCondition instanceof Condition.Permission) {
+ var condition = (Condition.Permission) genericCondition;
+ if (condition.getOwnerId() > 0) {
+ results.put(Permission.getKey(condition.getOwnerClass()), condition.getOwnerId());
+ } else {
+ results.put(Permission.getKey(condition.getPropertyClass()), condition.getPropertyId());
+ }
+ } else if (genericCondition instanceof Condition.LatestPositions) {
+ var condition = (Condition.LatestPositions) genericCondition;
+ if (condition.getDeviceId() > 0) {
+ results.put("deviceId", condition.getDeviceId());
+ }
}
return results;
}
- private String formatColumns(
- Columns columns, Class<?> clazz, String type, Function<String, String> mapper) {
- return columns.getColumns(clazz, type).stream().map(mapper).collect(Collectors.joining(", "));
+ private String formatColumns(List<String> columns, Function<String, String> mapper) {
+ return columns.stream().map(mapper).collect(Collectors.joining(", "));
}
- private String formatCondition(Condition genericCondition) {
+ private String formatCondition(Condition genericCondition) throws StorageException {
return formatCondition(genericCondition, true);
}
- private String formatCondition(Condition genericCondition, boolean appendWhere) {
+ private String formatCondition(Condition genericCondition, boolean appendWhere) throws StorageException {
StringBuilder result = new StringBuilder();
if (genericCondition != null) {
if (appendWhere) {
@@ -187,7 +251,7 @@ public class DatabaseStorage extends Storage {
}
if (genericCondition instanceof Condition.Compare) {
- Condition.Compare condition = (Condition.Compare) genericCondition;
+ var condition = (Condition.Compare) genericCondition;
result.append(condition.getColumn());
result.append(" ");
result.append(condition.getOperator());
@@ -196,7 +260,7 @@ public class DatabaseStorage extends Storage {
} else if (genericCondition instanceof Condition.Between) {
- Condition.Between condition = (Condition.Between) genericCondition;
+ var condition = (Condition.Between) genericCondition;
result.append(condition.getColumn());
result.append(" BETWEEN :");
result.append(condition.getFromVariable());
@@ -205,13 +269,31 @@ public class DatabaseStorage extends Storage {
} else if (genericCondition instanceof Condition.Binary) {
- Condition.Binary condition = (Condition.Binary) genericCondition;
+ var condition = (Condition.Binary) genericCondition;
result.append(formatCondition(condition.getFirst(), false));
result.append(" ");
result.append(condition.getOperator());
result.append(" ");
result.append(formatCondition(condition.getSecond(), false));
+ } else if (genericCondition instanceof Condition.Permission) {
+
+ var condition = (Condition.Permission) genericCondition;
+ result.append("id IN (");
+ result.append(formatPermissionQuery(condition));
+ result.append(")");
+
+ } else if (genericCondition instanceof Condition.LatestPositions) {
+
+ var condition = (Condition.LatestPositions) genericCondition;
+ result.append("id IN (");
+ result.append("SELECT positionId FROM ");
+ result.append(getStorageName(Device.class));
+ if (condition.getDeviceId() > 0) {
+ result.append(" WHERE id = :deviceId");
+ }
+ result.append(")");
+
}
}
return result.toString();
@@ -225,16 +307,103 @@ public class DatabaseStorage extends Storage {
if (order.getDescending()) {
result.append(" DESC");
}
+ if (order.getLimit() > 0) {
+ if (databaseType.equals("Microsoft SQL Server")) {
+ result.append(" OFFSET 0 ROWS FETCH FIRST ");
+ result.append(order.getLimit());
+ result.append(" ROWS ONLY");
+ } else {
+ result.append(" LIMIT ");
+ result.append(order.getLimit());
+ }
+ }
}
return result.toString();
}
- private String formatLimit(Limit limit) {
+ private String formatPermissionQuery(Condition.Permission condition) throws StorageException {
StringBuilder result = new StringBuilder();
- if (limit != null) {
- result.append(" LIMIT ");
- result.append(limit.getValue());
+
+ String outputKey;
+ String conditionKey;
+ if (condition.getOwnerId() > 0) {
+ outputKey = Permission.getKey(condition.getPropertyClass());
+ conditionKey = Permission.getKey(condition.getOwnerClass());
+ } else {
+ outputKey = Permission.getKey(condition.getOwnerClass());
+ conditionKey = Permission.getKey(condition.getPropertyClass());
}
+
+ String storageName = Permission.getStorageName(condition.getOwnerClass(), condition.getPropertyClass());
+ result.append("SELECT ");
+ result.append(storageName).append('.').append(outputKey);
+ result.append(" FROM ");
+ result.append(storageName);
+ result.append(" WHERE ");
+ result.append(conditionKey);
+ result.append(" = :");
+ result.append(conditionKey);
+
+ if (condition.getIncludeGroups()) {
+
+ boolean expandDevices;
+ String groupStorageName;
+ if (GroupedModel.class.isAssignableFrom(condition.getOwnerClass())) {
+ expandDevices = Device.class.isAssignableFrom(condition.getOwnerClass());
+ groupStorageName = Permission.getStorageName(Group.class, condition.getPropertyClass());
+ } else {
+ expandDevices = Device.class.isAssignableFrom(condition.getPropertyClass());
+ groupStorageName = Permission.getStorageName(condition.getOwnerClass(), Group.class);
+ }
+
+ result.append(" UNION ");
+
+ result.append("SELECT DISTINCT ");
+ if (!expandDevices) {
+ if (outputKey.equals("groupId")) {
+ result.append("all_groups.");
+ } else {
+ result.append(groupStorageName).append('.');
+ }
+ }
+ result.append(outputKey);
+ result.append(" FROM ");
+ result.append(groupStorageName);
+
+ result.append(" INNER JOIN (");
+ result.append("SELECT id as parentId, id as groupId FROM ");
+ result.append(getStorageName(Group.class));
+ result.append(" UNION ");
+ result.append("SELECT groupId as parentId, id as groupId FROM ");
+ result.append(getStorageName(Group.class));
+ result.append(" WHERE groupId IS NOT NULL");
+ result.append(" UNION ");
+ result.append("SELECT g2.groupId as parentId, g1.id as groupId FROM ");
+ result.append(getStorageName(Group.class));
+ result.append(" AS g2");
+ result.append(" INNER JOIN ");
+ result.append(getStorageName(Group.class));
+ result.append(" AS g1 ON g2.id = g1.groupId");
+ result.append(" WHERE g2.groupId IS NOT NULL");
+ result.append(") AS all_groups ON ");
+ result.append(groupStorageName);
+ result.append(".groupId = all_groups.parentId");
+
+ if (expandDevices) {
+ result.append(" INNER JOIN (");
+ result.append("SELECT groupId as parentId, id as deviceId FROM ");
+ result.append(getStorageName(Device.class));
+ result.append(" WHERE groupId IS NOT NULL");
+ result.append(") AS devices ON all_groups.groupId = devices.parentId");
+ }
+
+ result.append(" WHERE ");
+ result.append(conditionKey);
+ result.append(" = :");
+ result.append(conditionKey);
+
+ }
+
return result.toString();
}
diff --git a/src/main/java/org/traccar/storage/MemoryStorage.java b/src/main/java/org/traccar/storage/MemoryStorage.java
index 9cfe30a2b..9b5db1209 100644
--- a/src/main/java/org/traccar/storage/MemoryStorage.java
+++ b/src/main/java/org/traccar/storage/MemoryStorage.java
@@ -1,36 +1,172 @@
+/*
+ * Copyright 2022 - 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.traccar.storage;
+import org.traccar.model.BaseModel;
import org.traccar.model.Pair;
import org.traccar.model.Permission;
+import org.traccar.model.Server;
+import org.traccar.storage.query.Condition;
import org.traccar.storage.query.Request;
+import java.beans.Introspector;
+import java.lang.reflect.Method;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
public class MemoryStorage extends Storage {
+ private final Map<Class<?>, Map<Long, Object>> objects = new HashMap<>();
private final Map<Pair<Class<?>, Class<?>>, Set<Pair<Long, Long>>> permissions = new HashMap<>();
+ private final AtomicLong increment = new AtomicLong();
+
+ public MemoryStorage() {
+ Server server = new Server();
+ server.setId(1);
+ server.setRegistration(true);
+ objects.put(Server.class, Map.of(server.getId(), server));
+ }
+
@Override
public <T> List<T> getObjects(Class<T> clazz, Request request) {
- return null;
+ return objects.computeIfAbsent(clazz, key -> new HashMap<>()).values().stream()
+ .filter(object -> checkCondition(request.getCondition(), object))
+ .map(object -> (T) object)
+ .collect(Collectors.toList());
+ }
+
+ private boolean checkCondition(Condition genericCondition, Object object) {
+ if (genericCondition == null) {
+ return true;
+ }
+
+ if (genericCondition instanceof Condition.Compare) {
+
+ var condition = (Condition.Compare) genericCondition;
+ Object value = retrieveValue(object, condition.getVariable());
+ int result = ((Comparable) value).compareTo(condition.getValue());
+ switch (condition.getOperator()) {
+ case "<":
+ return result < 0;
+ case "<=":
+ return result <= 0;
+ case ">":
+ return result > 0;
+ case ">=":
+ return result >= 0;
+ case "=":
+ return result == 0;
+ default:
+ throw new RuntimeException("Unsupported comparison condition");
+ }
+
+ } else if (genericCondition instanceof Condition.Between) {
+
+ var condition = (Condition.Between) genericCondition;
+ Object fromValue = retrieveValue(object, condition.getFromVariable());
+ int fromResult = ((Comparable) fromValue).compareTo(condition.getFromValue());
+ Object toValue = retrieveValue(object, condition.getToVariable());
+ int toResult = ((Comparable) toValue).compareTo(condition.getToValue());
+ return fromResult >= 0 && toResult <= 0;
+
+ } else if (genericCondition instanceof Condition.Binary) {
+
+ var condition = (Condition.Binary) genericCondition;
+ if (condition.getOperator().equals("AND")) {
+ return checkCondition(condition.getFirst(), object) && checkCondition(condition.getSecond(), object);
+ } else if (condition.getOperator().equals("OR")) {
+ return checkCondition(condition.getFirst(), object) || checkCondition(condition.getSecond(), object);
+ }
+
+ } else if (genericCondition instanceof Condition.Permission) {
+
+ var condition = (Condition.Permission) genericCondition;
+ long id = (Long) retrieveValue(object, "id");
+ return getPermissionsSet(condition.getOwnerClass(), condition.getPropertyClass()).stream()
+ .anyMatch(pair -> {
+ if (condition.getOwnerId() > 0) {
+ return pair.getFirst() == condition.getOwnerId() && pair.getSecond() == id;
+ } else {
+ return pair.getFirst() == id && pair.getSecond() == condition.getPropertyId();
+ }
+ });
+
+ } else if (genericCondition instanceof Condition.LatestPositions) {
+
+ return false;
+
+ }
+
+ return false;
+ }
+
+ private Object retrieveValue(Object object, String key) {
+ try {
+ Method method = object.getClass().getMethod(
+ "get" + Character.toUpperCase(key.charAt(0)) + key.substring(1));
+ return method.invoke(object);
+ } catch (ReflectiveOperationException e) {
+ throw new RuntimeException(e);
+ }
}
@Override
public <T> long addObject(T entity, Request request) {
- return 0;
+ long id = increment.incrementAndGet();
+ objects.computeIfAbsent(entity.getClass(), key -> new HashMap<>()).put(id, entity);
+ return id;
}
@Override
public <T> void updateObject(T entity, Request request) {
+ Set<String> columns = new HashSet<>(request.getColumns().getColumns(entity.getClass(), "get"));
+ Collection<Object> items;
+ if (request.getCondition() != null) {
+ long id = (Long) ((Condition.Equals) request.getCondition()).getValue();
+ items = List.of(objects.computeIfAbsent(entity.getClass(), key -> new HashMap<>()).get(id));
+ } else {
+ items = objects.computeIfAbsent(entity.getClass(), key -> new HashMap<>()).values();
+ }
+ for (Method setter : entity.getClass().getMethods()) {
+ if (setter.getName().startsWith("set") && setter.getParameterCount() == 1
+ && columns.contains(Introspector.decapitalize(setter.getName()))) {
+ try {
+ Method getter = entity.getClass().getMethod(setter.getName().replaceFirst("set", "get"));
+ Object value = getter.invoke(entity);
+ for (Object object : items) {
+ setter.invoke(object, value);
+ }
+ } catch (ReflectiveOperationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
}
@Override
public void removeObject(Class<?> clazz, Request request) {
+ long id = (Long) ((Condition.Equals) request.getCondition()).getValue();
+ objects.computeIfAbsent(clazz, key -> new HashMap<>()).remove(id);
}
private Set<Pair<Long, Long>> getPermissionsSet(Class<?> ownerClass, Class<?> propertyClass) {
@@ -38,8 +174,12 @@ public class MemoryStorage extends Storage {
}
@Override
- public List<Permission> getPermissions(Class<?> ownerClass, Class<?> propertyClass) {
+ public List<Permission> getPermissions(
+ Class<? extends BaseModel> ownerClass, long ownerId,
+ Class<? extends BaseModel> propertyClass, long propertyId) {
return getPermissionsSet(ownerClass, propertyClass).stream()
+ .filter(pair -> ownerId == 0 || pair.getFirst().equals(ownerId))
+ .filter(pair -> propertyId == 0 || pair.getSecond().equals(propertyId))
.map(pair -> new Permission(ownerClass, pair.getFirst(), propertyClass, pair.getSecond()))
.collect(Collectors.toList());
}
diff --git a/src/main/java/org/traccar/storage/QueryBuilder.java b/src/main/java/org/traccar/storage/QueryBuilder.java
index da8002f0b..2f4c07406 100644
--- a/src/main/java/org/traccar/storage/QueryBuilder.java
+++ b/src/main/java/org/traccar/storage/QueryBuilder.java
@@ -16,9 +16,11 @@
package org.traccar.storage;
import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.Context;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
import org.traccar.model.Permission;
import javax.sql.DataSource;
@@ -40,17 +42,25 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+@SuppressWarnings("UnusedReturnValue")
public final class QueryBuilder {
private static final Logger LOGGER = LoggerFactory.getLogger(QueryBuilder.class);
+ private final Config config;
+ private final ObjectMapper objectMapper;
+
private final Map<String, List<Integer>> indexMap = new HashMap<>();
private Connection connection;
private PreparedStatement statement;
private final String query;
private final boolean returnGeneratedKeys;
- private QueryBuilder(DataSource dataSource, String query, boolean returnGeneratedKeys) throws SQLException {
+ private QueryBuilder(
+ Config config, DataSource dataSource, ObjectMapper objectMapper,
+ String query, boolean returnGeneratedKeys) throws SQLException {
+ this.config = config;
+ this.objectMapper = objectMapper;
this.query = query;
this.returnGeneratedKeys = returnGeneratedKeys;
if (query != null) {
@@ -125,13 +135,15 @@ public final class QueryBuilder {
return parsedQuery.toString();
}
- public static QueryBuilder create(DataSource dataSource, String query) throws SQLException {
- return new QueryBuilder(dataSource, query, false);
+ public static QueryBuilder create(
+ Config config, DataSource dataSource, ObjectMapper objectMapper, String query) throws SQLException {
+ return new QueryBuilder(config, dataSource, objectMapper, query, false);
}
public static QueryBuilder create(
- DataSource dataSource, String query, boolean returnGeneratedKeys) throws SQLException {
- return new QueryBuilder(dataSource, query, returnGeneratedKeys);
+ Config config, DataSource dataSource, ObjectMapper objectMapper, String query,
+ boolean returnGeneratedKeys) throws SQLException {
+ return new QueryBuilder(config, dataSource, objectMapper, query, returnGeneratedKeys);
}
private List<Integer> indexes(String name) {
@@ -271,35 +283,32 @@ public final class QueryBuilder {
return this;
}
- public QueryBuilder setObject(Object object) throws SQLException {
-
- Method[] methods = object.getClass().getMethods();
-
- for (Method method : methods) {
- if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) {
- String name = method.getName().substring(3);
- try {
- if (method.getReturnType().equals(boolean.class)) {
- setBoolean(name, (Boolean) method.invoke(object));
- } else if (method.getReturnType().equals(int.class)) {
- setInteger(name, (Integer) method.invoke(object));
- } else if (method.getReturnType().equals(long.class)) {
- setLong(name, (Long) method.invoke(object), name.endsWith("Id"));
- } else if (method.getReturnType().equals(double.class)) {
- setDouble(name, (Double) method.invoke(object));
- } else if (method.getReturnType().equals(String.class)) {
- setString(name, (String) method.invoke(object));
- } else if (method.getReturnType().equals(Date.class)) {
- setDate(name, (Date) method.invoke(object));
- } else if (method.getReturnType().equals(byte[].class)) {
- setBlob(name, (byte[]) method.invoke(object));
- } else {
- setString(name, Context.getObjectMapper().writeValueAsString(method.invoke(object)));
- }
- } catch (IllegalAccessException | InvocationTargetException | JsonProcessingException error) {
- LOGGER.warn("Get property error", error);
+ public QueryBuilder setObject(Object object, List<String> columns) throws SQLException {
+
+ try {
+ for (String column : columns) {
+ Method method = object.getClass().getMethod(
+ "get" + Character.toUpperCase(column.charAt(0)) + column.substring(1));
+ if (method.getReturnType().equals(boolean.class)) {
+ setBoolean(column, (Boolean) method.invoke(object));
+ } else if (method.getReturnType().equals(int.class)) {
+ setInteger(column, (Integer) method.invoke(object));
+ } else if (method.getReturnType().equals(long.class)) {
+ setLong(column, (Long) method.invoke(object), column.endsWith("Id"));
+ } else if (method.getReturnType().equals(double.class)) {
+ setDouble(column, (Double) method.invoke(object));
+ } else if (method.getReturnType().equals(String.class)) {
+ setString(column, (String) method.invoke(object));
+ } else if (method.getReturnType().equals(Date.class)) {
+ setDate(column, (Date) method.invoke(object));
+ } else if (method.getReturnType().equals(byte[].class)) {
+ setBlob(column, (byte[]) method.invoke(object));
+ } else {
+ setString(column, objectMapper.writeValueAsString(method.invoke(object)));
}
}
+ } catch (ReflectiveOperationException | JsonProcessingException e) {
+ LOGGER.warn("Set object error", e);
}
return this;
@@ -309,15 +318,6 @@ public final class QueryBuilder {
void process(T object, ResultSet resultSet) throws SQLException;
}
- public <T> T executeQuerySingle(Class<T> clazz) throws SQLException {
- List<T> result = executeQuery(clazz);
- if (!result.isEmpty()) {
- return result.iterator().next();
- } else {
- return null;
- }
- }
-
private <T> void addProcessors(
List<ResultSetProcessor<T>> processors,
final Class<?> parameterType, final Method method, final String name) {
@@ -386,7 +386,7 @@ public final class QueryBuilder {
String value = resultSet.getString(name);
if (value != null && !value.isEmpty()) {
try {
- method.invoke(object, Context.getObjectMapper().readValue(value, parameterType));
+ method.invoke(object, objectMapper.readValue(value, parameterType));
} catch (InvocationTargetException | IllegalAccessException | IOException error) {
LOGGER.warn("Set property error", error);
}
@@ -395,6 +395,12 @@ public final class QueryBuilder {
}
}
+ private void logQuery() {
+ if (config.getBoolean(Keys.LOGGER_QUERIES)) {
+ LOGGER.info(query);
+ }
+ }
+
public <T> List<T> executeQuery(Class<T> clazz) throws SQLException {
List<T> result = new LinkedList<>();
@@ -402,6 +408,8 @@ public final class QueryBuilder {
try {
+ logQuery();
+
try (ResultSet resultSet = statement.executeQuery()) {
ResultSetMetaData resultMetaData = resultSet.getMetaData();
@@ -457,6 +465,7 @@ public final class QueryBuilder {
if (query != null) {
try {
+ logQuery();
statement.execute();
if (returnGeneratedKeys) {
ResultSet resultSet = statement.getGeneratedKeys();
@@ -476,6 +485,7 @@ public final class QueryBuilder {
List<Permission> result = new LinkedList<>();
if (query != null) {
try {
+ logQuery();
try (ResultSet resultSet = statement.executeQuery()) {
ResultSetMetaData resultMetaData = resultSet.getMetaData();
while (resultSet.next()) {
diff --git a/src/main/java/org/traccar/storage/QueryExtended.java b/src/main/java/org/traccar/storage/QueryExtended.java
deleted file mode 100644
index 3796f1f40..000000000
--- a/src/main/java/org/traccar/storage/QueryExtended.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.storage;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface QueryExtended {
-}
diff --git a/src/main/java/org/traccar/storage/Storage.java b/src/main/java/org/traccar/storage/Storage.java
index 22c48cae0..55f5c22c0 100644
--- a/src/main/java/org/traccar/storage/Storage.java
+++ b/src/main/java/org/traccar/storage/Storage.java
@@ -1,5 +1,21 @@
+/*
+ * 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.storage;
+import org.traccar.model.BaseModel;
import org.traccar.model.Permission;
import org.traccar.storage.query.Request;
@@ -16,12 +32,19 @@ public abstract class Storage {
public abstract void removeObject(Class<?> clazz, Request request) throws StorageException;
public abstract List<Permission> getPermissions(
- Class<?> ownerClass, Class<?> propertyClass) throws StorageException;
+ Class<? extends BaseModel> ownerClass, long ownerId,
+ Class<? extends BaseModel> propertyClass, long propertyId) throws StorageException;
public abstract void addPermission(Permission permission) throws StorageException;
public abstract void removePermission(Permission permission) throws StorageException;
+ public List<Permission> getPermissions(
+ Class<? extends BaseModel> ownerClass,
+ Class<? extends BaseModel> propertyClass) throws StorageException {
+ return getPermissions(ownerClass, 0, propertyClass, 0);
+ }
+
public <T> T getObject(Class<T> clazz, Request request) throws StorageException {
var objects = getObjects(clazz, request);
return objects.isEmpty() ? null : objects.get(0);
diff --git a/src/main/java/org/traccar/storage/StorageException.java b/src/main/java/org/traccar/storage/StorageException.java
index 6c1e9c2ff..3f066cae6 100644
--- a/src/main/java/org/traccar/storage/StorageException.java
+++ b/src/main/java/org/traccar/storage/StorageException.java
@@ -1,3 +1,18 @@
+/*
+ * 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.storage;
public class StorageException extends Exception {
diff --git a/src/main/java/org/traccar/storage/StorageName.java b/src/main/java/org/traccar/storage/StorageName.java
index b6fa55e02..bf824c333 100644
--- a/src/main/java/org/traccar/storage/StorageName.java
+++ b/src/main/java/org/traccar/storage/StorageName.java
@@ -1,3 +1,18 @@
+/*
+ * 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.storage;
import java.lang.annotation.ElementType;
diff --git a/src/main/java/org/traccar/storage/query/Columns.java b/src/main/java/org/traccar/storage/query/Columns.java
index 196d2281c..a00400b36 100644
--- a/src/main/java/org/traccar/storage/query/Columns.java
+++ b/src/main/java/org/traccar/storage/query/Columns.java
@@ -1,8 +1,23 @@
+/*
+ * 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.storage.query;
-import org.traccar.storage.QueryExtended;
import org.traccar.storage.QueryIgnore;
+import java.beans.Introspector;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.LinkedList;
@@ -21,9 +36,8 @@ public abstract class Columns {
int parameterCount = type.equals("set") ? 1 : 0;
if (method.getName().startsWith(type) && method.getParameterTypes().length == parameterCount
&& !method.isAnnotationPresent(QueryIgnore.class)
- && !method.isAnnotationPresent(QueryExtended.class)
&& !method.getName().equals("getClass")) {
- columns.add(method.getName().substring(3).toLowerCase());
+ columns.add(Introspector.decapitalize(method.getName().substring(3)));
}
}
return columns;
diff --git a/src/main/java/org/traccar/storage/query/Condition.java b/src/main/java/org/traccar/storage/query/Condition.java
index 82c8e8479..08b199052 100644
--- a/src/main/java/org/traccar/storage/query/Condition.java
+++ b/src/main/java/org/traccar/storage/query/Condition.java
@@ -1,14 +1,41 @@
+/*
+ * 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.storage.query;
+import org.traccar.model.GroupedModel;
+
+import java.util.List;
+
public interface Condition {
- class Equals extends Compare {
- public Equals(String column, String variable) {
- this(column, variable, null);
+ static Condition merge(List<Condition> conditions) {
+ Condition result = null;
+ var iterator = conditions.iterator();
+ if (iterator.hasNext()) {
+ result = iterator.next();
+ while (iterator.hasNext()) {
+ result = new Condition.And(result, iterator.next());
+ }
}
+ return result;
+ }
- public Equals(String column, String variable, Object value) {
- super(column, "=", variable, value);
+ class Equals extends Compare {
+ public Equals(String column, Object value) {
+ super(column, "=", column, value);
}
}
@@ -114,4 +141,71 @@ public interface Condition {
}
}
+ class Permission implements Condition {
+ private final Class<?> ownerClass;
+ private final long ownerId;
+ private final Class<?> propertyClass;
+ private final long propertyId;
+ private final boolean excludeGroups;
+
+ private Permission(
+ Class<?> ownerClass, long ownerId, Class<?> propertyClass, long propertyId, boolean excludeGroups) {
+ this.ownerClass = ownerClass;
+ this.ownerId = ownerId;
+ this.propertyClass = propertyClass;
+ this.propertyId = propertyId;
+ this.excludeGroups = excludeGroups;
+ }
+
+ public Permission(Class<?> ownerClass, long ownerId, Class<?> propertyClass) {
+ this(ownerClass, ownerId, propertyClass, 0, false);
+ }
+
+ public Permission(Class<?> ownerClass, Class<?> propertyClass, long propertyId) {
+ this(ownerClass, 0, propertyClass, propertyId, false);
+ }
+
+ public Permission excludeGroups() {
+ return new Permission(this.ownerClass, this.ownerId, this.propertyClass, this.propertyId, true);
+ }
+
+ public Class<?> getOwnerClass() {
+ return ownerClass;
+ }
+
+ public long getOwnerId() {
+ return ownerId;
+ }
+
+ public Class<?> getPropertyClass() {
+ return propertyClass;
+ }
+
+ public long getPropertyId() {
+ return propertyId;
+ }
+
+ public boolean getIncludeGroups() {
+ boolean ownerGroupModel = GroupedModel.class.isAssignableFrom(ownerClass);
+ boolean propertyGroupModel = GroupedModel.class.isAssignableFrom(propertyClass);
+ return (ownerGroupModel || propertyGroupModel) && !excludeGroups;
+ }
+ }
+
+ class LatestPositions implements Condition {
+ private final long deviceId;
+
+ public LatestPositions(long deviceId) {
+ this.deviceId = deviceId;
+ }
+
+ public LatestPositions() {
+ this(0);
+ }
+
+ public long getDeviceId() {
+ return deviceId;
+ }
+ }
+
}
diff --git a/src/main/java/org/traccar/storage/query/Limit.java b/src/main/java/org/traccar/storage/query/Limit.java
index 4a20f0ce2..9673e5426 100644
--- a/src/main/java/org/traccar/storage/query/Limit.java
+++ b/src/main/java/org/traccar/storage/query/Limit.java
@@ -1,3 +1,18 @@
+/*
+ * 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.storage.query;
public class Limit {
diff --git a/src/main/java/org/traccar/storage/query/Order.java b/src/main/java/org/traccar/storage/query/Order.java
index 6852c5ba8..f10970381 100644
--- a/src/main/java/org/traccar/storage/query/Order.java
+++ b/src/main/java/org/traccar/storage/query/Order.java
@@ -1,17 +1,34 @@
+/*
+ * 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.storage.query;
public class Order {
private final String column;
private final boolean descending;
+ private final int limit;
public Order(String column) {
- this(false, column);
+ this(column, false, 0);
}
- public Order(boolean descending, String column) {
+ public Order(String column, boolean descending, int limit) {
this.column = column;
this.descending = descending;
+ this.limit = limit;
}
public String getColumn() {
@@ -22,4 +39,8 @@ public class Order {
return descending;
}
+ public int getLimit() {
+ return limit;
+ }
+
}
diff --git a/src/main/java/org/traccar/storage/query/Request.java b/src/main/java/org/traccar/storage/query/Request.java
index a98dd48f7..b9c2c963c 100644
--- a/src/main/java/org/traccar/storage/query/Request.java
+++ b/src/main/java/org/traccar/storage/query/Request.java
@@ -1,3 +1,18 @@
+/*
+ * 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.storage.query;
public class Request {
@@ -5,7 +20,6 @@ public class Request {
private final Columns columns;
private final Condition condition;
private final Order order;
- private final Limit limit;
public Request(Columns columns) {
this(columns, null, null);
@@ -19,15 +33,14 @@ public class Request {
this(columns, condition, null);
}
- public Request(Columns columns, Condition condition, Order order) {
- this(columns, condition, order, null);
+ public Request(Columns columns, Order order) {
+ this(columns, null, order);
}
- public Request(Columns columns, Condition condition, Order order, Limit limit) {
+ public Request(Columns columns, Condition condition, Order order) {
this.columns = columns;
this.condition = condition;
this.order = order;
- this.limit = limit;
}
public Columns getColumns() {
@@ -42,8 +55,4 @@ public class Request {
return order;
}
- public Limit getLimit() {
- return limit;
- }
-
}
diff --git a/src/main/java/org/traccar/web/ConsoleServlet.java b/src/main/java/org/traccar/web/ConsoleServlet.java
index 0f3dcd8fd..0012ba077 100644
--- a/src/main/java/org/traccar/web/ConsoleServlet.java
+++ b/src/main/java/org/traccar/web/ConsoleServlet.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,33 +16,39 @@
package org.traccar.web;
import org.h2.server.web.ConnectionInfo;
-import org.h2.server.web.WebServlet;
+import org.h2.server.web.JakartaWebServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.Context;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-public class ConsoleServlet extends WebServlet {
+public class ConsoleServlet extends JakartaWebServlet {
private static final Logger LOGGER = LoggerFactory.getLogger(ConsoleServlet.class);
+ private final Config config;
+
+ public ConsoleServlet(Config config) {
+ this.config = config;
+ }
+
@Override
public void init() {
super.init();
try {
- Field field = WebServlet.class.getDeclaredField("server");
+ Field field = JakartaWebServlet.class.getDeclaredField("server");
field.setAccessible(true);
org.h2.server.web.WebServer server = (org.h2.server.web.WebServer) field.get(this);
ConnectionInfo connectionInfo = new ConnectionInfo("Traccar|"
- + Context.getConfig().getString(Keys.DATABASE_DRIVER) + "|"
- + Context.getConfig().getString(Keys.DATABASE_URL) + "|"
- + Context.getConfig().getString(Keys.DATABASE_USER));
+ + config.getString(Keys.DATABASE_DRIVER) + "|"
+ + config.getString(Keys.DATABASE_URL) + "|"
+ + config.getString(Keys.DATABASE_USER));
Method method;
diff --git a/src/main/java/org/traccar/web/ModernDefaultServlet.java b/src/main/java/org/traccar/web/ModernDefaultServlet.java
new file mode 100644
index 000000000..a7c8cdb29
--- /dev/null
+++ b/src/main/java/org/traccar/web/ModernDefaultServlet.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.web;
+
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.util.resource.Resource;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import jakarta.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+
+public class ModernDefaultServlet extends DefaultServlet {
+
+ private Resource overrideResource;
+
+ @Inject
+ public ModernDefaultServlet(Config config) {
+ String override = config.getString(Keys.WEB_OVERRIDE);
+ if (override != null) {
+ overrideResource = Resource.newResource(new File(override));
+ }
+ }
+
+ @Override
+ public Resource getResource(String pathInContext) {
+ if (overrideResource != null) {
+ try {
+ Resource override = overrideResource.addPath(pathInContext);
+ if (override.exists()) {
+ return override;
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return super.getResource(pathInContext.indexOf('.') < 0 ? "/" : pathInContext);
+ }
+
+ @Override
+ public String getWelcomeFile(String pathInContext) {
+ return super.getWelcomeFile("/");
+ }
+
+}
diff --git a/src/main/java/org/traccar/web/OverrideFilter.java b/src/main/java/org/traccar/web/OverrideFilter.java
new file mode 100644
index 000000000..f870c4147
--- /dev/null
+++ b/src/main/java/org/traccar/web/OverrideFilter.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.web;
+
+import com.google.inject.Provider;
+import org.traccar.api.security.PermissionsService;
+import org.traccar.model.Server;
+import org.traccar.storage.StorageException;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Singleton
+public class OverrideFilter implements Filter {
+
+ private final Provider<PermissionsService> permissionsServiceProvider;
+
+ @Inject
+ public OverrideFilter(Provider<PermissionsService> permissionsServiceProvider) {
+ this.permissionsServiceProvider = permissionsServiceProvider;
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+
+ if (((HttpServletRequest) request).getServletPath().startsWith("/api")) {
+ chain.doFilter(request, response);
+ return;
+ }
+
+ ResponseWrapper wrappedResponse = new ResponseWrapper((HttpServletResponse) response);
+
+ chain.doFilter(request, wrappedResponse);
+
+ byte[] bytes = wrappedResponse.getCapture();
+ if (bytes != null) {
+ if (wrappedResponse.getContentType() != null && wrappedResponse.getContentType().contains("text/html")
+ || ((HttpServletRequest) request).getPathInfo().endsWith("manifest.json")) {
+
+ Server server;
+ try {
+ server = permissionsServiceProvider.get().getServer();
+ } catch (StorageException e) {
+ throw new RuntimeException(e);
+ }
+
+ String title = server.getString("title", "Traccar");
+ String description = server.getString("description", "Traccar GPS Tracking System");
+ String colorPrimary = server.getString("colorPrimary", "#1a237e");
+
+ String alteredContent = new String(wrappedResponse.getCapture())
+ .replace("${title}", title)
+ .replace("${description}", description)
+ .replace("${colorPrimary}", colorPrimary);
+
+ response.setContentLength(alteredContent.length());
+ response.getOutputStream().write(alteredContent.getBytes());
+
+ } else {
+ response.getOutputStream().write(bytes);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/web/ResponseWrapper.java b/src/main/java/org/traccar/web/ResponseWrapper.java
new file mode 100644
index 000000000..a0eaf6788
--- /dev/null
+++ b/src/main/java/org/traccar/web/ResponseWrapper.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.web;
+
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.WriteListener;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletResponseWrapper;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class ResponseWrapper extends HttpServletResponseWrapper {
+
+ private final ByteArrayOutputStream capture;
+ private ServletOutputStream output;
+
+ public ResponseWrapper(HttpServletResponse response) {
+ super(response);
+ capture = new ByteArrayOutputStream(response.getBufferSize());
+ }
+
+ @Override
+ public ServletOutputStream getOutputStream() {
+ if (output == null) {
+ output = new ServletOutputStream() {
+ @Override
+ public boolean isReady() {
+ return true;
+ }
+
+ @Override
+ public void setWriteListener(WriteListener writeListener) {
+ }
+
+ @Override
+ public void write(int b) {
+ capture.write(b);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ capture.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ capture.close();
+ }
+ };
+ }
+ return output;
+ }
+
+ @Override
+ public void flushBuffer() throws IOException {
+ super.flushBuffer();
+ if (output != null) {
+ output.flush();
+ }
+ }
+
+ public byte[] getCapture() throws IOException {
+ if (output != null) {
+ output.close();
+ return capture.toByteArray();
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/web/ThrottlingFilter.java b/src/main/java/org/traccar/web/ThrottlingFilter.java
new file mode 100644
index 000000000..1bad33db6
--- /dev/null
+++ b/src/main/java/org/traccar/web/ThrottlingFilter.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2022 - 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.web;
+
+import org.eclipse.jetty.servlets.DoSFilter;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpSession;
+
+@Singleton
+public class ThrottlingFilter extends DoSFilter {
+
+ @Inject
+ private Config config;
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ super.init(filterConfig);
+ if (config.hasKey(Keys.WEB_MAX_REQUESTS_PER_SECOND)) {
+ setMaxRequestsPerSec(config.getInteger(Keys.WEB_MAX_REQUESTS_PER_SECOND));
+ }
+ setMaxRequestMs(config.getInteger(Keys.WEB_MAX_REQUEST_SECONDS) * 1000L);
+ }
+
+ @Override
+ protected String extractUserId(ServletRequest request) {
+ HttpSession session = ((HttpServletRequest) request).getSession(false);
+ if (session != null) {
+ var userId = session.getAttribute("userId");
+ return userId != null ? userId.toString() : null;
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/org/traccar/web/WebInjectionManagerFactory.java b/src/main/java/org/traccar/web/WebInjectionManagerFactory.java
new file mode 100644
index 000000000..3e73c41ad
--- /dev/null
+++ b/src/main/java/org/traccar/web/WebInjectionManagerFactory.java
@@ -0,0 +1,50 @@
+/*
+ * 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.web;
+
+import org.glassfish.hk2.api.ServiceLocator;
+import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.InjectionManagerFactory;
+import org.jvnet.hk2.guice.bridge.api.GuiceBridge;
+import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge;
+import org.traccar.Main;
+
+import jakarta.annotation.Priority;
+
+@Priority(20)
+public class WebInjectionManagerFactory implements InjectionManagerFactory {
+
+ private final InjectionManagerFactory originalFactory = new Hk2InjectionManagerFactory();
+
+ private InjectionManager injectGuiceBridge(InjectionManager injectionManager) {
+ var serviceLocator = injectionManager.getInstance(ServiceLocator.class);
+ GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
+ var guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
+ guiceBridge.bridgeGuiceInjector(Main.getInjector());
+ return injectionManager;
+ }
+
+ @Override
+ public InjectionManager create() {
+ return injectGuiceBridge(originalFactory.create());
+ }
+
+ @Override
+ public InjectionManager create(Object parent) {
+ return injectGuiceBridge(originalFactory.create(parent));
+ }
+}
diff --git a/src/main/java/org/traccar/web/WebModule.java b/src/main/java/org/traccar/web/WebModule.java
new file mode 100644
index 000000000..a32a6f447
--- /dev/null
+++ b/src/main/java/org/traccar/web/WebModule.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2022 - 2023 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.web;
+
+import com.google.inject.servlet.ServletModule;
+import org.traccar.api.AsyncSocketServlet;
+import org.traccar.api.MediaFilter;
+
+public class WebModule extends ServletModule {
+
+ @Override
+ protected void configureServlets() {
+ filter("/*").through(OverrideFilter.class);
+ filter("/api/*").through(ThrottlingFilter.class);
+ filter("/api/media/*").through(MediaFilter.class);
+ serve("/api/socket").with(AsyncSocketServlet.class);
+ }
+}
diff --git a/src/main/java/org/traccar/web/WebServer.java b/src/main/java/org/traccar/web/WebServer.java
index 0ed5d013e..5f27f7662 100644
--- a/src/main/java/org/traccar/web/WebServer.java
+++ b/src/main/java/org/traccar/web/WebServer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2023 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
*/
package org.traccar.web;
+import com.google.inject.Injector;
+import com.google.inject.servlet.GuiceFilter;
import org.eclipse.jetty.http.HttpCookie;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
@@ -35,35 +37,27 @@ import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
-import org.glassfish.jersey.inject.hk2.ImmediateHk2InjectionManager;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
-import org.glassfish.jersey.server.spi.Container;
-import org.glassfish.jersey.server.spi.ContainerLifecycleListener;
import org.glassfish.jersey.servlet.ServletContainer;
-import org.jvnet.hk2.guice.bridge.api.GuiceBridge;
-import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.Context;
import org.traccar.LifecycleObject;
-import org.traccar.Main;
-import org.traccar.api.DateParameterConverterProvider;
-import org.traccar.config.Config;
-import org.traccar.api.AsyncSocketServlet;
import org.traccar.api.CorsResponseFilter;
-import org.traccar.api.MediaFilter;
-import org.traccar.api.ObjectMapperProvider;
+import org.traccar.api.DateParameterConverterProvider;
import org.traccar.api.ResourceErrorHandler;
-import org.traccar.api.security.SecurityRequestFilter;
import org.traccar.api.resource.ServerResource;
+import org.traccar.api.security.SecurityRequestFilter;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
-
-import javax.servlet.DispatcherType;
-import javax.servlet.ServletException;
-import javax.servlet.SessionCookieConfig;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import org.traccar.helper.ObjectMapperContextResolver;
+
+import jakarta.servlet.DispatcherType;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.SessionCookieConfig;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
@@ -74,10 +68,13 @@ public class WebServer implements LifecycleObject {
private static final Logger LOGGER = LoggerFactory.getLogger(WebServer.class);
- private Server server;
-
- private void initServer(Config config) {
+ private final Injector injector;
+ private final Config config;
+ private final Server server;
+ public WebServer(Injector injector, Config config) {
+ this.injector = injector;
+ this.config = config;
String address = config.getString(Keys.WEB_ADDRESS);
int port = config.getInteger(Keys.WEB_PORT);
if (address == null) {
@@ -85,22 +82,19 @@ public class WebServer implements LifecycleObject {
} else {
server = new Server(new InetSocketAddress(address, port));
}
- }
-
- public WebServer(Config config) {
-
- initServer(config);
ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ JettyWebSocketServletContainerInitializer.configure(servletHandler, null);
+ servletHandler.addFilter(GuiceFilter.class, "/*", EnumSet.allOf(DispatcherType.class));
- initApi(config, servletHandler);
- initSessionConfig(config, servletHandler);
+ initApi(servletHandler);
+ initSessionConfig(servletHandler);
if (config.getBoolean(Keys.WEB_CONSOLE)) {
- servletHandler.addServlet(new ServletHolder(new ConsoleServlet()), "/console/*");
+ servletHandler.addServlet(new ServletHolder(new ConsoleServlet(config)), "/console/*");
}
- initWebApp(config, servletHandler);
+ initWebApp(servletHandler);
servletHandler.setErrorHandler(new ErrorHandler() {
@Override
@@ -112,12 +106,12 @@ public class WebServer implements LifecycleObject {
});
HandlerList handlers = new HandlerList();
- initClientProxy(config, handlers);
+ initClientProxy(handlers);
handlers.addHandler(servletHandler);
handlers.addHandler(new GzipHandler());
server.setHandler(handlers);
- if (config.getBoolean(Keys.WEB_REQUEST_LOG_ENABLE)) {
+ if (config.hasKey(Keys.WEB_REQUEST_LOG_PATH)) {
RequestLogWriter logWriter = new RequestLogWriter(config.getString(Keys.WEB_REQUEST_LOG_PATH));
logWriter.setAppend(true);
logWriter.setRetainDays(config.getInteger(Keys.WEB_REQUEST_LOG_RETAIN_DAYS));
@@ -126,7 +120,7 @@ public class WebServer implements LifecycleObject {
}
}
- private void initClientProxy(Config config, HandlerList handlers) {
+ private void initClientProxy(HandlerList handlers) {
int port = config.getInteger(Keys.PROTOCOL_PORT.withPrefix("osmand"));
if (port != 0) {
ServletContextHandler servletHandler = new ServletContextHandler() {
@@ -139,15 +133,15 @@ public class WebServer implements LifecycleObject {
}
}
};
- ServletHolder servletHolder = new ServletHolder(new AsyncProxyServlet.Transparent());
+ ServletHolder servletHolder = new ServletHolder(AsyncProxyServlet.Transparent.class);
servletHolder.setInitParameter("proxyTo", "http://localhost:" + port);
servletHandler.addServlet(servletHolder, "/");
handlers.addHandler(servletHandler);
}
}
- private void initWebApp(Config config, ServletContextHandler servletHandler) {
- ServletHolder servletHolder = new ServletHolder(DefaultServlet.class);
+ private void initWebApp(ServletContextHandler servletHandler) {
+ ServletHolder servletHolder = new ServletHolder(new ModernDefaultServlet(config));
servletHolder.setInitParameter("resourceBase", new File(config.getString(Keys.WEB_PATH)).getAbsolutePath());
servletHolder.setInitParameter("dirAllowed", "false");
if (config.getBoolean(Keys.WEB_DEBUG)) {
@@ -162,10 +156,7 @@ public class WebServer implements LifecycleObject {
servletHandler.addServlet(servletHolder, "/*");
}
- private void initApi(Config config, ServletContextHandler servletHandler) {
- servletHandler.addServlet(new ServletHolder(new AsyncSocketServlet()), "/api/socket");
- JettyWebSocketServletContainerInitializer.configure(servletHandler, null);
-
+ private void initApi(ServletContextHandler servletHandler) {
String mediaPath = config.getString(Keys.MEDIA_PATH);
if (mediaPath != null) {
ServletHolder servletHolder = new ServletHolder(DefaultServlet.class);
@@ -173,39 +164,27 @@ public class WebServer implements LifecycleObject {
servletHolder.setInitParameter("dirAllowed", "false");
servletHolder.setInitParameter("pathInfoOnly", "true");
servletHandler.addServlet(servletHolder, "/api/media/*");
- servletHandler.addFilter(MediaFilter.class, "/api/media/*", EnumSet.allOf(DispatcherType.class));
}
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.registerClasses(
- JacksonFeature.class, ObjectMapperProvider.class, ResourceErrorHandler.class,
- SecurityRequestFilter.class, CorsResponseFilter.class, DateParameterConverterProvider.class);
+ JacksonFeature.class,
+ ObjectMapperContextResolver.class,
+ DateParameterConverterProvider.class,
+ SecurityRequestFilter.class,
+ CorsResponseFilter.class,
+ ResourceErrorHandler.class);
resourceConfig.packages(ServerResource.class.getPackage().getName());
- resourceConfig.register(new ContainerLifecycleListener() {
- @Override
- public void onStartup(Container container) {
- var injectionManager = container.getApplicationHandler().getInjectionManager();
- var serviceLocator = ((ImmediateHk2InjectionManager) injectionManager).getServiceLocator();
- GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
- var guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
- guiceBridge.bridgeGuiceInjector(Main.getInjector());
- }
-
- @Override
- public void onReload(Container container) {
- }
-
- @Override
- public void onShutdown(Container container) {
- }
- });
+ if (resourceConfig.getClasses().stream().filter(ServerResource.class::equals).findAny().isEmpty()) {
+ LOGGER.warn("Failed to load API resources");
+ }
servletHandler.addServlet(new ServletHolder(new ServletContainer(resourceConfig)), "/api/*");
}
- private void initSessionConfig(Config config, ServletContextHandler servletHandler) {
+ private void initSessionConfig(ServletContextHandler servletHandler) {
if (config.getBoolean(Keys.WEB_PERSIST_SESSION)) {
DatabaseAdaptor databaseAdaptor = new DatabaseAdaptor();
- databaseAdaptor.setDatasource(Context.getDataManager().getDataSource());
+ databaseAdaptor.setDatasource(injector.getInstance(DataSource.class));
JDBCSessionDataStoreFactory jdbcSessionDataStoreFactory = new JDBCSessionDataStoreFactory();
jdbcSessionDataStoreFactory.setDatabaseAdaptor(databaseAdaptor);
SessionHandler sessionHandler = servletHandler.getSessionHandler();
@@ -214,14 +193,16 @@ public class WebServer implements LifecycleObject {
sessionHandler.setSessionCache(sessionCache);
}
+ SessionCookieConfig sessionCookieConfig = servletHandler.getServletContext().getSessionCookieConfig();
+
int sessionTimeout = config.getInteger(Keys.WEB_SESSION_TIMEOUT);
if (sessionTimeout > 0) {
servletHandler.getSessionHandler().setMaxInactiveInterval(sessionTimeout);
+ sessionCookieConfig.setMaxAge(sessionTimeout);
}
String sameSiteCookie = config.getString(Keys.WEB_SAME_SITE_COOKIE);
if (sameSiteCookie != null) {
- SessionCookieConfig sessionCookieConfig = servletHandler.getServletContext().getSessionCookieConfig();
switch (sameSiteCookie.toLowerCase()) {
case "lax":
sessionCookieConfig.setComment(HttpCookie.SAME_SITE_LAX_COMMENT);
@@ -240,21 +221,13 @@ public class WebServer implements LifecycleObject {
}
@Override
- public void start() {
- try {
- server.start();
- } catch (Exception error) {
- LOGGER.warn("Web server start failed", error);
- }
+ public void start() throws Exception {
+ server.start();
}
@Override
- public void stop() {
- try {
- server.stop();
- } catch (Exception error) {
- LOGGER.warn("Web server stop failed", error);
- }
+ public void stop() throws Exception {
+ server.stop();
}
}
diff --git a/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory b/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory
new file mode 100644
index 000000000..ce0a70630
--- /dev/null
+++ b/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory
@@ -0,0 +1 @@
+org.traccar.web.WebInjectionManagerFactory
diff --git a/src/main/resources/META-INF/services/org.jxls.expression.ExpressionEvaluatorFactory b/src/main/resources/META-INF/services/org.jxls.expression.ExpressionEvaluatorFactory
new file mode 100644
index 000000000..75d628857
--- /dev/null
+++ b/src/main/resources/META-INF/services/org.jxls.expression.ExpressionEvaluatorFactory
@@ -0,0 +1 @@
+org.traccar.reports.common.ExpressionEvaluatorFactory
diff --git a/src/test/java/org/traccar/BaseTest.java b/src/test/java/org/traccar/BaseTest.java
index 0b2c616ce..2ace781f3 100644
--- a/src/test/java/org/traccar/BaseTest.java
+++ b/src/test/java/org/traccar/BaseTest.java
@@ -1,34 +1,69 @@
package org.traccar;
-import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import org.traccar.config.Config;
+import org.traccar.database.CommandsManager;
import org.traccar.database.MediaManager;
+import org.traccar.database.StatisticsManager;
+import org.traccar.model.Device;
+import org.traccar.session.ConnectionManager;
+import org.traccar.session.DeviceSession;
+import org.traccar.session.cache.CacheManager;
-import java.util.HashMap;
-import java.util.Map;
+import java.net.SocketAddress;
+import java.util.HashSet;
-public class BaseTest {
-
- public static class MockMediaManager extends MediaManager {
- Map<String, ByteBuf> files = new HashMap<>();
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
- MockMediaManager() {
- super("");
- }
+public class BaseTest {
- @Override
- public String writeFile(String uniqueId, ByteBuf buf, String extension) {
- String fileName = uniqueId + "/mock." + extension;
- files.put(fileName, buf);
- return fileName;
- }
+ protected <T extends BaseProtocolDecoder> T inject(T decoder) throws Exception {
+ var config = new Config();
+ decoder.setConfig(config);
+ var device = mock(Device.class);
+ when(device.getId()).thenReturn(1L);
+ var cacheManager = mock(CacheManager.class);
+ when(cacheManager.getConfig()).thenReturn(config);
+ when(cacheManager.getObject(eq(Device.class), anyLong())).thenReturn(device);
+ decoder.setCacheManager(cacheManager);
+ var connectionManager = mock(ConnectionManager.class);
+ var uniqueIdsProvided = new HashSet<Boolean>();
+ when(connectionManager.getDeviceSession(any(), any(), any(), any(String[].class))).thenAnswer(invocation -> {
+ var mock = new DeviceSession(1L, "", mock(Protocol.class), mock(Channel.class), mock(SocketAddress.class));
+ if (uniqueIdsProvided.isEmpty()) {
+ if (invocation.getArguments().length > 3) {
+ uniqueIdsProvided.add(true);
+ return mock;
+ }
+ return null;
+ } else {
+ return mock;
+ }
+ });
+ decoder.setConnectionManager(connectionManager);
+ decoder.setStatisticsManager(mock(StatisticsManager.class));
+ decoder.setMediaManager(mock(MediaManager.class));
+ decoder.setCommandsManager(mock(CommandsManager.class));
+ return decoder;
+ }
- public ByteBuf readFile(String fileName) {
- return files.get(fileName);
- }
+ protected <T extends BaseFrameDecoder> T inject(T decoder) throws Exception {
+ return decoder;
}
- static {
- Context.init(new TestIdentityManager(), new MockMediaManager());
+ protected <T extends BaseProtocolEncoder> T inject(T encoder) throws Exception {
+ var device = mock(Device.class);
+ when(device.getId()).thenReturn(1L);
+ when(device.getUniqueId()).thenReturn("123456789012345");
+ var cacheManager = mock(CacheManager.class);
+ when(cacheManager.getConfig()).thenReturn(mock(Config.class));
+ when(cacheManager.getObject(eq(Device.class), anyLong())).thenReturn(device);
+ encoder.setCacheManager(cacheManager);
+ return encoder;
}
}
diff --git a/src/test/java/org/traccar/ProtocolTest.java b/src/test/java/org/traccar/ProtocolTest.java
index 353593c29..3b04b5e02 100644
--- a/src/test/java/org/traccar/ProtocolTest.java
+++ b/src/test/java/org/traccar/ProtocolTest.java
@@ -14,6 +14,7 @@ import org.traccar.helper.DataConverter;
import org.traccar.model.CellTower;
import org.traccar.model.Command;
import org.traccar.model.Position;
+import org.traccar.model.WifiAccessPoint;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
@@ -25,11 +26,11 @@ import java.util.List;
import java.util.Map;
import java.util.TimeZone;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class ProtocolTest extends BaseTest {
@@ -111,7 +112,7 @@ public class ProtocolTest extends BaseTest {
Object decodedObject = decoder.decode(null, null, object);
Position position;
if (decodedObject instanceof Collection) {
- position = (Position) ((Collection) decodedObject).iterator().next();
+ position = (Position) ((Collection<?>) decodedObject).iterator().next();
} else {
position = (Position) decodedObject;
}
@@ -154,11 +155,11 @@ public class ProtocolTest extends BaseTest {
private void verifyDecodedList(Object decodedObject, boolean checkLocation, Position expected) {
- assertNotNull("list is null", decodedObject);
- assertTrue("not a list", decodedObject instanceof List);
- assertFalse("list is empty", ((List) decodedObject).isEmpty());
+ assertNotNull(decodedObject, "list is null");
+ assertTrue(decodedObject instanceof List, "not a list");
+ assertFalse(((List<?>) decodedObject).isEmpty(), "list is empty");
- for (Object item : (List) decodedObject) {
+ for (Object item : (List<?>) decodedObject) {
verifyDecodedPosition(item, checkLocation, false, expected);
}
@@ -166,8 +167,8 @@ public class ProtocolTest extends BaseTest {
private void verifyDecodedPosition(Object decodedObject, boolean checkLocation, boolean checkAttributes, Position expected) {
- assertNotNull("position is null", decodedObject);
- assertTrue("not a position", decodedObject instanceof Position);
+ assertNotNull(decodedObject, "position is null");
+ assertTrue(decodedObject instanceof Position, "not a position");
Position position = (Position) decodedObject;
@@ -178,47 +179,46 @@ public class ProtocolTest extends BaseTest {
if (expected.getFixTime() != null) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- assertEquals("time", dateFormat.format(expected.getFixTime()), dateFormat.format(position.getFixTime()));
+ assertEquals(dateFormat.format(expected.getFixTime()), dateFormat.format(position.getFixTime()), "time");
}
- assertEquals("valid", expected.getValid(), position.getValid());
- assertEquals("latitude", expected.getLatitude(), position.getLatitude(), 0.00001);
- assertEquals("longitude", expected.getLongitude(), position.getLongitude(), 0.00001);
+ assertEquals(expected.getValid(), position.getValid(), "valid");
+ assertEquals(expected.getLatitude(), position.getLatitude(), 0.00001, "latitude");
+ assertEquals(expected.getLongitude(), position.getLongitude(), 0.00001, "longitude");
} else {
assertNotNull(position.getServerTime());
assertNotNull(position.getFixTime());
- assertTrue("year > 1999", position.getFixTime().after(new Date(915148800000L)));
- assertTrue("time < +25 hours",
- position.getFixTime().getTime() < System.currentTimeMillis() + 25 * 3600000);
+ assertTrue(position.getFixTime().after(new Date(915148800000L)), "year > 1999");
+ assertTrue(position.getFixTime().getTime() < System.currentTimeMillis() + 25 * 3600000, "time < +25 h");
- assertTrue("latitude >= -90", position.getLatitude() >= -90);
- assertTrue("latitude <= 90", position.getLatitude() <= 90);
+ assertTrue(position.getLatitude() >= -90, "latitude >= -90");
+ assertTrue(position.getLatitude() <= 90, "latitude <= 90");
- assertTrue("longitude >= -180", position.getLongitude() >= -180);
- assertTrue("longitude <= 180", position.getLongitude() <= 180);
+ assertTrue(position.getLongitude() >= -180, "longitude >= -180");
+ assertTrue(position.getLongitude() <= 180, "longitude <= 180");
}
- assertTrue("altitude >= -12262", position.getAltitude() >= -12262);
- assertTrue("altitude <= 18000", position.getAltitude() <= 18000);
+ assertTrue(position.getAltitude() >= -12262, "altitude >= -12262");
+ assertTrue(position.getAltitude() <= 18000, "altitude <= 18000");
- assertTrue("speed >= 0", position.getSpeed() >= 0);
- assertTrue("speed <= 869", position.getSpeed() <= 869);
+ assertTrue(position.getSpeed() >= 0, "speed >= 0");
+ assertTrue(position.getSpeed() <= 869, "speed <= 869");
- assertTrue("course >= 0", position.getCourse() >= 0);
- assertTrue("course <= 360", position.getCourse() <= 360);
+ assertTrue(position.getCourse() >= 0, "course >= 0");
+ assertTrue(position.getCourse() <= 360, "course <= 360");
- assertNotNull("protocol is null", position.getProtocol());
+ assertNotNull(position.getProtocol(), "protocol is null");
- assertTrue("deviceId > 0", position.getDeviceId() > 0);
+ assertTrue(position.getDeviceId() > 0, "deviceId > 0");
}
Map<String, Object> attributes = position.getAttributes();
if (checkAttributes) {
- assertFalse("no attributes", attributes.isEmpty());
+ assertFalse(attributes.isEmpty(), "no attributes");
}
if (attributes.containsKey(Position.KEY_INDEX)) {
@@ -310,23 +310,31 @@ public class ProtocolTest extends BaseTest {
assertTrue(attributes.get(Position.KEY_RESULT) instanceof String);
}
- if (position.getNetwork() != null && position.getNetwork().getCellTowers() != null) {
- for (CellTower cellTower : position.getNetwork().getCellTowers()) {
- checkInteger(cellTower.getMobileCountryCode(), 0, 999);
- checkInteger(cellTower.getMobileNetworkCode(), 0, 999);
- checkInteger(cellTower.getLocationAreaCode(), 1, 65535);
- checkInteger(cellTower.getCellId(), 0, 268435455);
+ if (position.getNetwork() != null) {
+ if (position.getNetwork().getCellTowers() != null) {
+ for (CellTower cellTower : position.getNetwork().getCellTowers()) {
+ checkInteger(cellTower.getMobileCountryCode(), 0, 999);
+ checkInteger(cellTower.getMobileNetworkCode(), 0, 999);
+ checkInteger(cellTower.getLocationAreaCode(), 1, 65535);
+ checkInteger(cellTower.getCellId(), 0, 268435455);
+ }
+ }
+
+ if (position.getNetwork().getWifiAccessPoints() != null) {
+ for (WifiAccessPoint wifiAccessPoint : position.getNetwork().getWifiAccessPoints()) {
+ assertTrue(wifiAccessPoint.getMacAddress().matches("((\\p{XDigit}{2}):){5}(\\p{XDigit}{2})"));
+ }
}
}
}
private void checkInteger(Object value, int min, int max) {
- assertNotNull("value is null", value);
- assertTrue("not int or long", value instanceof Integer || value instanceof Long);
+ assertNotNull(value, "value is null");
+ assertTrue(value instanceof Integer || value instanceof Long, "not int or long");
long number = ((Number) value).longValue();
- assertTrue("value too low", number >= min);
- assertTrue("value too high", number <= max);
+ assertTrue(number >= min, "value too low");
+ assertTrue(number <= max, "value too high");
}
protected void verifyCommand(
@@ -335,8 +343,8 @@ public class ProtocolTest extends BaseTest {
}
protected void verifyFrame(ByteBuf expected, Object object) {
- assertNotNull("buffer is null", object);
- assertTrue("not a buffer", object instanceof ByteBuf);
+ assertNotNull(object, "buffer is null");
+ assertTrue(object instanceof ByteBuf, "not a buffer");
assertEquals(ByteBufUtil.hexDump(expected), ByteBufUtil.hexDump((ByteBuf) object));
}
diff --git a/src/test/java/org/traccar/TestIdentityManager.java b/src/test/java/org/traccar/TestIdentityManager.java
deleted file mode 100644
index 7d2865e74..000000000
--- a/src/test/java/org/traccar/TestIdentityManager.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package org.traccar;
-
-import org.traccar.database.IdentityManager;
-import org.traccar.model.Device;
-import org.traccar.model.Position;
-
-public final class TestIdentityManager implements IdentityManager {
-
- private static Device createDevice() {
- Device device = new Device();
- device.setId(1);
- device.setName("test");
- device.setUniqueId("123456789012345");
- return device;
- }
-
- @Override
- public long addUnknownDevice(String uniqueId) {
- return 1;
- }
-
- @Override
- public Device getById(long id) {
- return createDevice();
- }
-
- @Override
- public Device getByUniqueId(String uniqueId) {
- return createDevice();
- }
-
- @Override
- public String getDevicePassword(long id, String protocol, String defaultPassword) {
- return defaultPassword;
- }
-
- @Override
- public Position getLastPosition(long deviceId) {
- return null;
- }
-
- @Override
- public boolean isLatestPosition(Position position) {
- return true;
- }
-
- @Override
- public boolean lookupAttributeBoolean(
- long deviceId, String attributeName, boolean defaultValue, boolean lookupServer, boolean lookupConfig) {
- return defaultValue;
- }
-
- @Override
- public String lookupAttributeString(
- long deviceId, String attributeName, String defaultValue, boolean lookupServer, boolean lookupConfig) {
- if (attributeName.equals("filter.skipAttributes")) {
- return "alarm,result";
- }
- return defaultValue;
- }
-
- @Override
- public int lookupAttributeInteger(
- long deviceId, String attributeName, int defaultValue, boolean lookupServer, boolean lookupConfig) {
- return defaultValue;
- }
-
- @Override
- public long lookupAttributeLong(
- long deviceId, String attributeName, long defaultValue, boolean lookupServer, boolean lookupConfig) {
- return defaultValue;
- }
-
- @Override
- public double lookupAttributeDouble(
- long deviceId, String attributeName, double defaultValue, boolean lookupServer, boolean lookupConfig) {
- return defaultValue;
- }
-
-}
diff --git a/src/test/java/org/traccar/WebDataHandlerTest.java b/src/test/java/org/traccar/WebDataHandlerTest.java
deleted file mode 100644
index cfbd71f23..000000000
--- a/src/test/java/org/traccar/WebDataHandlerTest.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.traccar;
-
-import org.junit.Test;
-import org.traccar.config.Config;
-import org.traccar.config.Keys;
-import org.traccar.model.Position;
-
-import static org.junit.Assert.assertEquals;
-
-public class WebDataHandlerTest extends ProtocolTest {
-
- @Test
- public void testFormatRequest() throws Exception {
-
- Config config = new Config();
- config.setString(Keys.FORWARD_URL, "http://localhost/?fixTime={fixTime}&gprmc={gprmc}&name={name}");
-
- Position position = position("2016-01-01 01:02:03.000", true, 20, 30);
-
- WebDataHandler handler = new WebDataHandler(config, Context.getIdentityManager(), null, null);
-
- assertEquals(
- "http://localhost/?fixTime=1451610123000&gprmc=$GPRMC,010203.000,A,2000.0000,N,03000.0000,E,0.00,0.00,010116,,*05&name=test",
- handler.formatRequest(position));
-
- }
-
-}
diff --git a/src/test/java/org/traccar/calendar/CalendarTest.java b/src/test/java/org/traccar/calendar/CalendarTest.java
index 56406d4b8..4106f89a9 100644
--- a/src/test/java/org/traccar/calendar/CalendarTest.java
+++ b/src/test/java/org/traccar/calendar/CalendarTest.java
@@ -1,5 +1,9 @@
package org.traccar.calendar;
+import net.fortuna.ical4j.data.ParserException;
+import org.junit.jupiter.api.Test;
+import org.traccar.model.Calendar;
+
import java.io.IOException;
import java.sql.SQLException;
import java.text.DateFormat;
@@ -7,12 +11,8 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
-import org.junit.Test;
-import org.traccar.model.Calendar;
-
-import net.fortuna.ical4j.data.ParserException;
-
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class CalendarTest {
@@ -46,14 +46,12 @@ public class CalendarTest {
calendar.setData(calendarString.getBytes());
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssX");
- Date date = format.parse("2016-12-13 22:59:59+05");
- assertTrue(!calendar.checkMoment(date));
- date = format.parse("2016-12-13 23:00:01+05");
- assertTrue(calendar.checkMoment(date));
+ assertFalse(calendar.checkMoment(format.parse("2016-12-13 22:59:59+05")));
+ assertTrue(calendar.checkMoment(format.parse("2016-12-13 23:00:01+05")));
+ assertTrue(calendar.checkMoment(format.parse("2016-12-13 06:59:59+05")));
+ assertFalse(calendar.checkMoment(format.parse("2016-12-13 07:00:01+05")));
- date = format.parse("2016-12-13 06:59:59+05");
- assertTrue(calendar.checkMoment(date));
- date = format.parse("2016-12-13 07:00:01+05");
- assertTrue(!calendar.checkMoment(date));
+ var periods = calendar.findPeriods(format.parse("2016-12-13 06:59:59+05"));
+ assertFalse(periods.isEmpty());
}
}
diff --git a/src/test/java/org/traccar/config/ConfigTest.java b/src/test/java/org/traccar/config/ConfigTest.java
index 13d0ffb04..f48e79acf 100644
--- a/src/test/java/org/traccar/config/ConfigTest.java
+++ b/src/test/java/org/traccar/config/ConfigTest.java
@@ -1,8 +1,8 @@
package org.traccar.config;
-import org.junit.Test;
-import static org.junit.Assert.assertEquals;
-import org.traccar.config.Config;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class ConfigTest {
diff --git a/src/test/java/org/traccar/database/GroupTreeTest.java b/src/test/java/org/traccar/database/GroupTreeTest.java
index b547aab60..7c0d478f8 100644
--- a/src/test/java/org/traccar/database/GroupTreeTest.java
+++ b/src/test/java/org/traccar/database/GroupTreeTest.java
@@ -1,13 +1,13 @@
package org.traccar.database;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.model.Device;
import org.traccar.model.Group;
import java.util.ArrayList;
import java.util.Collection;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class GroupTreeTest {
diff --git a/src/test/java/org/traccar/forward/PositionForwarderUrlTest.java b/src/test/java/org/traccar/forward/PositionForwarderUrlTest.java
new file mode 100644
index 000000000..f0e354620
--- /dev/null
+++ b/src/test/java/org/traccar/forward/PositionForwarderUrlTest.java
@@ -0,0 +1,42 @@
+package org.traccar.forward;
+
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.model.Device;
+import org.traccar.model.Position;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class PositionForwarderUrlTest extends ProtocolTest {
+
+ @Test
+ public void testFormatRequest() throws Exception {
+
+ Config config = new Config();
+ config.setString(Keys.FORWARD_URL, "http://localhost/?fixTime={fixTime}&gprmc={gprmc}&name={name}");
+
+ Position position = position("2016-01-01 01:02:03.000", true, 20, 30);
+
+ var device = mock(Device.class);
+ when(device.getId()).thenReturn(1L);
+ when(device.getName()).thenReturn("test");
+ when(device.getUniqueId()).thenReturn("123456789012345");
+ when(device.getStatus()).thenReturn(Device.STATUS_ONLINE);
+
+ PositionData positionData = new PositionData();
+ positionData.setPosition(position);
+ positionData.setDevice(device);
+
+ PositionForwarderUrl forwarder = new PositionForwarderUrl(config, null, null);
+
+ assertEquals(
+ "http://localhost/?fixTime=1451610123000&gprmc=$GPRMC,010203.000,A,2000.0000,N,03000.0000,E,0.00,0.00,010116,,*05&name=test",
+ forwarder.formatRequest(positionData));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/geocoder/AddressFormatTest.java b/src/test/java/org/traccar/geocoder/AddressFormatTest.java
index 0cc5168ef..b3a248bb3 100644
--- a/src/test/java/org/traccar/geocoder/AddressFormatTest.java
+++ b/src/test/java/org/traccar/geocoder/AddressFormatTest.java
@@ -1,8 +1,8 @@
package org.traccar.geocoder;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class AddressFormatTest {
diff --git a/src/test/java/org/traccar/geocoder/GeocoderTest.java b/src/test/java/org/traccar/geocoder/GeocoderTest.java
index 91431fd6a..1e1a98c1e 100644
--- a/src/test/java/org/traccar/geocoder/GeocoderTest.java
+++ b/src/test/java/org/traccar/geocoder/GeocoderTest.java
@@ -1,11 +1,13 @@
package org.traccar.geocoder;
-import java.util.Locale;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
-import org.junit.Ignore;
-import org.junit.Test;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+import java.util.Locale;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class GeocoderTest {
@@ -13,107 +15,109 @@ public class GeocoderTest {
Locale.setDefault(Locale.US);
}
- @Ignore
+ private final Client client = ClientBuilder.newClient();
+
+ @Disabled
@Test
public void testGoogle() {
- Geocoder geocoder = new GoogleGeocoder(null, null, 0, new AddressFormat());
+ Geocoder geocoder = new GoogleGeocoder(client, null, null, 0, new AddressFormat());
String address = geocoder.getAddress(31.776797, 35.211489, null);
assertEquals("1 Ibn Shaprut St, Jerusalem, Jerusalem District, IL", address);
}
- @Ignore
+ @Disabled
@Test
public void testNominatim() {
- Geocoder geocoder = new NominatimGeocoder(null, null, null, 0, new AddressFormat());
+ Geocoder geocoder = new NominatimGeocoder(client, null, null, null, 0, new AddressFormat());
String address = geocoder.getAddress(40.7337807, -73.9974401, null);
assertEquals("35 West 9th Street, NYC, New York, US", address);
}
- @Ignore
+ @Disabled
@Test
public void testGisgraphy() {
- Geocoder geocoder = new GisgraphyGeocoder(null, 0, new AddressFormat());
+ Geocoder geocoder = new GisgraphyGeocoder(client, null, 0, new AddressFormat());
String address = geocoder.getAddress(48.8530000, 2.3400000, null);
assertEquals("Rue du Jardinet, Paris, ÃŽle-de-France, FR", address);
}
- @Ignore
+ @Disabled
@Test
public void testOpenCage() {
Geocoder geocoder = new OpenCageGeocoder(
- "http://api.opencagedata.com/geocode/v1", "SECRET", null, 0, new AddressFormat());
+ client, "http://api.opencagedata.com/geocode/v1", "SECRET", null, 0, new AddressFormat());
String address = geocoder.getAddress(34.116302, -118.051519, null);
assertEquals("Charleston Road, California, US", address);
}
- @Ignore
+ @Disabled
@Test
public void testGeocodeFarm() {
- Geocoder geocoder = new GeocodeFarmGeocoder(null, null, 0, new AddressFormat());
+ Geocoder geocoder = new GeocodeFarmGeocoder(client, null, null, 0, new AddressFormat());
String address = geocoder.getAddress(34.116302, -118.051519, null);
assertEquals("Estrella Avenue, Arcadia, California, United States", address);
}
- @Ignore
+ @Disabled
@Test
public void testGeocodeXyz() {
- Geocoder geocoder = new GeocodeXyzGeocoder(null, 0, new AddressFormat());
+ Geocoder geocoder = new GeocodeXyzGeocoder(client, null, 0, new AddressFormat());
String address = geocoder.getAddress(34.116302, -118.051519, null);
assertEquals("605 ESTRELLA AVE, ARCADIA, California United States of America, US", address);
}
- @Ignore
+ @Disabled
@Test
public void testBan() {
- Geocoder geocoder = new BanGeocoder(0, new AddressFormat("%f [%d], %c"));
+ Geocoder geocoder = new BanGeocoder(client, 0, new AddressFormat("%f [%d], %c"));
String address = geocoder.getAddress(48.8575, 2.2944, null);
assertEquals("8 Avenue Gustave Eiffel 75007 Paris [75, Paris, ÃŽle-de-France], FR", address);
}
- @Ignore
+ @Disabled
@Test
public void testHere() {
- Geocoder geocoder = new HereGeocoder(null, "", "", null, 0, new AddressFormat());
+ Geocoder geocoder = new HereGeocoder(client, null, "", "", null, 0, new AddressFormat());
String address = geocoder.getAddress(48.8575, 2.2944, null);
assertEquals("6 Avenue Gustave Eiffel, Paris, ÃŽle-de-France, FRA", address);
}
- @Ignore
+ @Disabled
@Test
public void testMapmyIndia() {
- Geocoder geocoder = new MapmyIndiaGeocoder("", "", 0, new AddressFormat("%f"));
+ Geocoder geocoder = new MapmyIndiaGeocoder(client, "", "", 0, new AddressFormat("%f"));
String address = geocoder.getAddress(28.6129602407977, 77.2294557094574, null);
assertEquals("New Delhi, Delhi. 1 m from India Gate pin-110001 (India)", address);
}
- @Ignore
+ @Disabled
@Test
public void testPositionStack() {
- Geocoder geocoder = new PositionStackGeocoder("", 0, new AddressFormat("%f"));
+ Geocoder geocoder = new PositionStackGeocoder(client, "", 0, new AddressFormat("%f"));
String address = geocoder.getAddress(28.6129602407977, 77.2294557094574, null);
assertEquals("India Gate, New Delhi, India", address);
}
- @Ignore
+ @Disabled
@Test
public void testMapbox() {
- Geocoder geocoder = new MapboxGeocoder("", 0, new AddressFormat("%f"));
+ Geocoder geocoder = new MapboxGeocoder(client, "", 0, new AddressFormat("%f"));
String address = geocoder.getAddress(40.733, -73.989, null);
assertEquals("120 East 13th Street, New York, New York 10003, United States", address);
}
- @Ignore
+ @Disabled
@Test
public void testMapTiler() {
- Geocoder geocoder = new MapTilerGeocoder("", 0, new AddressFormat());
+ Geocoder geocoder = new MapTilerGeocoder(client, "", 0, new AddressFormat());
String address = geocoder.getAddress(40.733, -73.989, null);
assertEquals("East 13th Street, New York City, New York, United States", address);
}
- @Ignore
+ @Disabled
@Test
public void testGeoapify() {
- Geocoder geocoder = new GeoapifyGeocoder("", null, 0, new AddressFormat());
+ Geocoder geocoder = new GeoapifyGeocoder(client, "", null, 0, new AddressFormat());
String address = geocoder.getAddress(40.733, -73.989, null);
assertEquals("114 East 13th Street, New York, New York, US", address);
}
diff --git a/src/test/java/org/traccar/geofence/GeofenceCircleTest.java b/src/test/java/org/traccar/geofence/GeofenceCircleTest.java
index 259a8fb77..106b041fc 100644
--- a/src/test/java/org/traccar/geofence/GeofenceCircleTest.java
+++ b/src/test/java/org/traccar/geofence/GeofenceCircleTest.java
@@ -1,28 +1,27 @@
package org.traccar.geofence;
-import java.text.ParseException;
+import org.junit.jupiter.api.Test;
-import org.junit.Test;
+import java.text.ParseException;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class GeofenceCircleTest {
@Test
public void testCircleWkt() throws ParseException {
String test = "CIRCLE (55.75414 37.6204, 100)";
- GeofenceGeometry geofenceGeometry = new GeofenceCircle();
- geofenceGeometry.fromWkt(test);
+ GeofenceGeometry geofenceGeometry = new GeofenceCircle(test);
assertEquals(geofenceGeometry.toWkt(), test);
}
@Test
public void testContainsCircle() throws ParseException {
- String test = "CIRCLE (55.75414 37.6204, 100)";
- GeofenceGeometry geofenceGeometry = new GeofenceCircle();
- geofenceGeometry.fromWkt(test);
- assertTrue(geofenceGeometry.containsPoint(55.75477, 37.62025));
- assertTrue(!geofenceGeometry.containsPoint(55.75545, 37.61921));
+ GeofenceGeometry geofenceGeometry = new GeofenceCircle("CIRCLE (55.75414 37.6204, 100)");
+ assertTrue(geofenceGeometry.containsPoint(null, null, 55.75477, 37.62025));
+ assertFalse(geofenceGeometry.containsPoint(null, null, 55.75545, 37.61921));
}
+
}
diff --git a/src/test/java/org/traccar/geofence/GeofencePolygonTest.java b/src/test/java/org/traccar/geofence/GeofencePolygonTest.java
index cc9c46c94..bbf19cc38 100644
--- a/src/test/java/org/traccar/geofence/GeofencePolygonTest.java
+++ b/src/test/java/org/traccar/geofence/GeofencePolygonTest.java
@@ -1,12 +1,12 @@
package org.traccar.geofence;
-import java.text.ParseException;
+import org.junit.jupiter.api.Test;
-import org.junit.Test;
+import java.text.ParseException;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class GeofencePolygonTest {
@@ -19,41 +19,34 @@ public class GeofencePolygonTest {
@Test
public void testPolygonWkt() throws ParseException {
String test = "POLYGON ((55.75474 37.61823, 55.75513 37.61888, 55.7535 37.6222, 55.75315 37.62165))";
- GeofenceGeometry geofenceGeometry = new GeofencePolygon();
- geofenceGeometry.fromWkt(test);
+ GeofenceGeometry geofenceGeometry = new GeofencePolygon(test);
assertEquals(geofenceGeometry.toWkt(), test);
}
@Test
public void testContainsPolygon() throws ParseException {
- String test = "POLYGON ((55.75474 37.61823, 55.75513 37.61888, 55.7535 37.6222, 55.75315 37.62165))";
- GeofenceGeometry geofenceGeometry = new GeofencePolygon();
- geofenceGeometry.fromWkt(test);
- assertTrue(geofenceGeometry.containsPoint(55.75476, 37.61915));
- assertFalse(geofenceGeometry.containsPoint(55.75545, 37.61921));
-
+ GeofenceGeometry geofenceGeometry = new GeofencePolygon(
+ "POLYGON ((55.75474 37.61823, 55.75513 37.61888, 55.7535 37.6222, 55.75315 37.62165))");
+ assertTrue(geofenceGeometry.containsPoint(null, null, 55.75476, 37.61915));
+ assertFalse(geofenceGeometry.containsPoint(null, null, 55.75545, 37.61921));
}
@Test
public void testContainsPolygon180() throws ParseException {
- String test = "POLYGON ((66.9494 179.838, 66.9508 -179.8496, 66.8406 -180.0014))";
- GeofenceGeometry geofenceGeometry = new GeofencePolygon();
- geofenceGeometry.fromWkt(test);
- assertTrue(geofenceGeometry.containsPoint(66.9015, -180.0096));
- assertTrue(geofenceGeometry.containsPoint(66.9015, 179.991));
- assertFalse(geofenceGeometry.containsPoint(66.8368, -179.8792));
-
+ GeofenceGeometry geofenceGeometry = new GeofencePolygon(
+ "POLYGON ((66.9494 179.838, 66.9508 -179.8496, 66.8406 -180.0014))");
+ assertTrue(geofenceGeometry.containsPoint(null, null, 66.9015, -180.0096));
+ assertTrue(geofenceGeometry.containsPoint(null, null, 66.9015, 179.991));
+ assertFalse(geofenceGeometry.containsPoint(null, null, 66.8368, -179.8792));
}
@Test
public void testContainsPolygon0() throws ParseException {
- String test = "POLYGON ((51.1966 -0.6207, 51.1897 0.4147, 50.9377 0.5136, 50.8675 -0.6082))";
- GeofenceGeometry geofenceGeometry = new GeofencePolygon();
- geofenceGeometry.fromWkt(test);
- assertTrue(geofenceGeometry.containsPoint(51.0466, -0.0165));
- assertTrue(geofenceGeometry.containsPoint(51.0466, 0.018));
- assertFalse(geofenceGeometry.containsPoint(50.9477, 0.5836));
-
+ GeofenceGeometry geofenceGeometry = new GeofencePolygon(
+ "POLYGON ((51.1966 -0.6207, 51.1897 0.4147, 50.9377 0.5136, 50.8675 -0.6082))");
+ assertTrue(geofenceGeometry.containsPoint(null, null, 51.0466, -0.0165));
+ assertTrue(geofenceGeometry.containsPoint(null, null, 51.0466, 0.018));
+ assertFalse(geofenceGeometry.containsPoint(null, null, 50.9477, 0.5836));
}
}
diff --git a/src/test/java/org/traccar/geofence/GeofencePolylineTest.java b/src/test/java/org/traccar/geofence/GeofencePolylineTest.java
index 1e9dcb7c3..9b7bbb7d1 100644
--- a/src/test/java/org/traccar/geofence/GeofencePolylineTest.java
+++ b/src/test/java/org/traccar/geofence/GeofencePolylineTest.java
@@ -1,47 +1,59 @@
package org.traccar.geofence;
-import java.text.ParseException;
+import org.junit.jupiter.api.Test;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.model.Geofence;
-import org.junit.Test;
+import java.text.ParseException;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class GeofencePolylineTest {
@Test
public void testPolylineWkt() throws ParseException {
String test = "LINESTRING (55.75474 37.61823, 55.75513 37.61888, 55.7535 37.6222, 55.75315 37.62165)";
- GeofenceGeometry geofenceGeometry = new GeofencePolyline();
- geofenceGeometry.fromWkt(test);
+ GeofenceGeometry geofenceGeometry = new GeofencePolyline(test);
assertEquals(geofenceGeometry.toWkt(), test);
}
@Test
public void testContainsPolyline1Interval() throws ParseException {
- String test = "LINESTRING (56.83777 60.59833, 56.83766 60.5968)";
- GeofenceGeometry geofenceGeometry = new GeofencePolyline(test, 35);
- assertTrue(geofenceGeometry.containsPoint(56.83801, 60.59748));
- ((GeofencePolyline) geofenceGeometry).setDistance(15);
- assertTrue(!geofenceGeometry.containsPoint(56.83801, 60.59748));
+ GeofenceGeometry geofenceGeometry = new GeofencePolyline(
+ "LINESTRING (56.83777 60.59833, 56.83766 60.5968)");
+ Config config = mock(Config.class);
+ when(config.getDouble(Keys.GEOFENCE_POLYLINE_DISTANCE)).thenReturn(35.0);
+ assertTrue(geofenceGeometry.containsPoint(config, mock(Geofence.class), 56.83801, 60.59748));
+ when(config.getDouble(Keys.GEOFENCE_POLYLINE_DISTANCE)).thenReturn(15.0);
+ assertFalse(geofenceGeometry.containsPoint(config, mock(Geofence.class), 56.83801, 60.59748));
}
@Test
public void testContainsPolyline3Intervals() throws ParseException {
- String test = "LINESTRING (56.836 60.6126, 56.8393 60.6114, 56.83887 60.60811, 56.83782 60.5988)";
- GeofenceGeometry geofenceGeometry = new GeofencePolyline(test, 15);
- assertTrue(geofenceGeometry.containsPoint(56.83847, 60.60458));
- assertTrue(!geofenceGeometry.containsPoint(56.83764, 60.59725));
- assertTrue(!geofenceGeometry.containsPoint(56.83861, 60.60822));
+ GeofenceGeometry geofenceGeometry = new GeofencePolyline(
+ "LINESTRING (56.836 60.6126, 56.8393 60.6114, 56.83887 60.60811, 56.83782 60.5988)");
+ Config config = mock(Config.class);
+ when(config.getDouble(Keys.GEOFENCE_POLYLINE_DISTANCE)).thenReturn(15.0);
+ assertTrue(geofenceGeometry.containsPoint(config, mock(Geofence.class), 56.83847, 60.60458));
+ assertFalse(geofenceGeometry.containsPoint(config, mock(Geofence.class), 56.83764, 60.59725));
+ assertFalse(geofenceGeometry.containsPoint(config, mock(Geofence.class), 56.83861, 60.60822));
}
@Test
public void testContainsPolylineNear180() throws ParseException {
- String test = "LINESTRING (66.9494 179.838, 66.9508 -179.8496)";
- GeofenceGeometry geofenceGeometry = new GeofencePolyline(test, 25);
- assertTrue(geofenceGeometry.containsPoint(66.95, 180.0));
- assertTrue(!geofenceGeometry.containsPoint(66.96, 180.0));
- assertTrue(!geofenceGeometry.containsPoint(66.9509, -179.83));
+ GeofenceGeometry geofenceGeometry = new GeofencePolyline(
+ "LINESTRING (66.9494 179.838, 66.9508 -179.8496)");
+ Config config = mock(Config.class);
+ when(config.getDouble(Keys.GEOFENCE_POLYLINE_DISTANCE)).thenReturn(25.0);
+ assertTrue(geofenceGeometry.containsPoint(config, mock(Geofence.class), 66.95, 180.0));
+ assertFalse(geofenceGeometry.containsPoint(config, mock(Geofence.class), 66.96, 180.0));
+ assertFalse(geofenceGeometry.containsPoint(config, mock(Geofence.class), 66.9509, -179.83));
}
+
}
diff --git a/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java b/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java
index 2729052d6..da5ae3340 100644
--- a/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java
+++ b/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java
@@ -1,24 +1,25 @@
package org.traccar.geolocation;
-import org.junit.Ignore;
-import org.junit.Test;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
import org.traccar.BaseTest;
import org.traccar.model.CellTower;
import org.traccar.model.Network;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
public class GeolocationProviderTest extends BaseTest {
- @Ignore
- @Test
- public void test() throws Exception {
- testLocationProvider();
- }
+ private final Client client = ClientBuilder.newClient();
- public void testLocationProvider() throws Exception {
- MozillaGeolocationProvider provider = new MozillaGeolocationProvider(null);
+ @Disabled
+ @Test
+ public void testMozilla() throws Exception {
+ MozillaGeolocationProvider provider = new MozillaGeolocationProvider(client, null);
Network network = new Network(CellTower.from(208, 1, 2, 1234567));
diff --git a/src/test/java/org/traccar/handler/ComputedAttributesTest.java b/src/test/java/org/traccar/handler/ComputedAttributesTest.java
index a76d8169b..e2af703c2 100644
--- a/src/test/java/org/traccar/handler/ComputedAttributesTest.java
+++ b/src/test/java/org/traccar/handler/ComputedAttributesTest.java
@@ -1,20 +1,20 @@
package org.traccar.handler;
-import java.util.Date;
-
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.config.Config;
import org.traccar.model.Attribute;
import org.traccar.model.Position;
-import static org.junit.Assert.assertEquals;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class ComputedAttributesTest {
@Test
public void testComputedAttributes() {
- ComputedAttributesHandler handler = new ComputedAttributesHandler(new Config(), null, null);
+ ComputedAttributesHandler handler = new ComputedAttributesHandler(new Config(), null);
Date date = new Date();
Position position = new Position();
@@ -41,7 +41,7 @@ public class ComputedAttributesTest {
attribute.setExpression("(bitFlag & 4) != 0");
assertEquals(true, handler.computeAttribute(attribute, position));
- attribute.setExpression("if (event == 42) \"lowBattery\"");
+ attribute.setExpression("event == 42 ? \"lowBattery\" : null");
assertEquals("lowBattery", handler.computeAttribute(attribute, position));
attribute.setExpression("speed > 5 && valid");
diff --git a/src/test/java/org/traccar/handler/DistanceHandlerTest.java b/src/test/java/org/traccar/handler/DistanceHandlerTest.java
index f7c6e42cd..7d2f1e2e3 100644
--- a/src/test/java/org/traccar/handler/DistanceHandlerTest.java
+++ b/src/test/java/org/traccar/handler/DistanceHandlerTest.java
@@ -1,17 +1,19 @@
package org.traccar.handler;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.config.Config;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
public class DistanceHandlerTest {
@Test
public void testCalculateDistance() {
- DistanceHandler distanceHandler = new DistanceHandler(new Config(), null);
+ DistanceHandler distanceHandler = new DistanceHandler(new Config(), mock(CacheManager.class));
Position position = distanceHandler.handlePosition(new Position());
diff --git a/src/test/java/org/traccar/handler/FilterHandlerTest.java b/src/test/java/org/traccar/handler/FilterHandlerTest.java
index ad8d244a6..36bb84f19 100644
--- a/src/test/java/org/traccar/handler/FilterHandlerTest.java
+++ b/src/test/java/org/traccar/handler/FilterHandlerTest.java
@@ -1,87 +1,99 @@
package org.traccar.handler;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
import org.traccar.BaseTest;
import org.traccar.config.Config;
import org.traccar.config.Keys;
+import org.traccar.model.Device;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
import java.util.Date;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class FilterHandlerTest extends BaseTest {
- private FilterHandler passingHandler = new FilterHandler(new Config());
+ private FilterHandler passingHandler;
private FilterHandler filteringHandler;
- @Before
- public void before() {
- Config config = new Config();
- config.setString(Keys.FILTER_INVALID, String.valueOf(true));
- config.setString(Keys.FILTER_ZERO, String.valueOf(true));
- config.setString(Keys.FILTER_DUPLICATE, String.valueOf(true));
- config.setString(Keys.FILTER_FUTURE, String.valueOf(5 * 60));
- config.setString(Keys.FILTER_APPROXIMATE, String.valueOf(true));
- config.setString(Keys.FILTER_STATIC, String.valueOf(true));
- config.setString(Keys.FILTER_DISTANCE, String.valueOf(10));
- config.setString(Keys.FILTER_MAX_SPEED, String.valueOf(500));
- config.setString(Keys.FILTER_SKIP_LIMIT, String.valueOf(10));
- config.setString(Keys.FILTER_SKIP_ATTRIBUTES_ENABLE, String.valueOf(true));
- filteringHandler = new FilterHandler(config);
+ @BeforeEach
+ public void passingHandler() {
+ var config = mock(Config.class);
+ when(config.getBoolean(Keys.FILTER_ENABLE)).thenReturn(true);
+ var cacheManager = mock(CacheManager.class);
+ when(cacheManager.getConfig()).thenReturn(config);
+ when(cacheManager.getObject(any(), anyLong())).thenReturn(mock(Device.class));
+ passingHandler = new FilterHandler(config, cacheManager, null, null);
}
- private Position createPosition(
- long deviceId,
- Date time,
- boolean valid,
- double latitude,
- double longitude,
- double altitude,
- double speed,
- double course) {
+ @BeforeEach
+ public void filteringHandler() {
+ var config = mock(Config.class);
+ when(config.getBoolean(Keys.FILTER_ENABLE)).thenReturn(true);
+ when(config.getBoolean(Keys.FILTER_INVALID)).thenReturn(true);
+ when(config.getBoolean(Keys.FILTER_ZERO)).thenReturn(true);
+ when(config.getBoolean(Keys.FILTER_DUPLICATE)).thenReturn(true);
+ when(config.getLong(Keys.FILTER_FUTURE)).thenReturn(5 * 60L);
+ when(config.getBoolean(Keys.FILTER_APPROXIMATE)).thenReturn(true);
+ when(config.getBoolean(Keys.FILTER_STATIC)).thenReturn(true);
+ when(config.getInteger(Keys.FILTER_DISTANCE)).thenReturn(10);
+ when(config.getInteger(Keys.FILTER_MAX_SPEED)).thenReturn(500);
+ when(config.getLong(Keys.FILTER_SKIP_LIMIT)).thenReturn(10L);
+ when(config.getBoolean(Keys.FILTER_SKIP_ATTRIBUTES_ENABLE)).thenReturn(true);
+ when(config.getString(Keys.FILTER_SKIP_ATTRIBUTES.getKey())).thenReturn("alarm,result");
+ var cacheManager = mock(CacheManager.class);
+ when(cacheManager.getConfig()).thenReturn(config);
+ when(cacheManager.getObject(any(), anyLong())).thenReturn(mock(Device.class));
+ filteringHandler = new FilterHandler(config, cacheManager, null, null);
+ }
+ private Position createPosition(Date time, boolean valid, double speed) {
Position position = new Position();
- position.setDeviceId(deviceId);
+ position.setDeviceId(0);
position.setTime(time);
position.setValid(valid);
- position.setLatitude(latitude);
- position.setLongitude(longitude);
- position.setAltitude(altitude);
+ position.setLatitude(10);
+ position.setLongitude(10);
+ position.setAltitude(10);
position.setSpeed(speed);
- position.setCourse(course);
+ position.setCourse(10);
return position;
}
@Test
public void testFilter() {
- Position position = createPosition(0, new Date(), true, 10, 10, 10, 10, 10);
+ Position position = createPosition(new Date(), true, 10);
- assertNotNull(filteringHandler.handlePosition(position));
- assertNotNull(passingHandler.handlePosition(position));
+ assertFalse(filteringHandler.filter(position));
+ assertFalse(passingHandler.filter(position));
- position = createPosition(0, new Date(Long.MAX_VALUE), true, 10, 10, 10, 10, 10);
+ position = createPosition(new Date(Long.MAX_VALUE), true, 10);
- assertNull(filteringHandler.handlePosition(position));
- assertNotNull(passingHandler.handlePosition(position));
+ assertTrue(filteringHandler.filter(position));
+ assertFalse(passingHandler.filter(position));
- position = createPosition(0, new Date(), false, 10, 10, 10, 10, 10);
+ position = createPosition(new Date(), false, 10);
- assertNull(filteringHandler.handlePosition(position));
- assertNotNull(passingHandler.handlePosition(position));
+ assertTrue(filteringHandler.filter(position));
+ assertFalse(passingHandler.filter(position));
}
@Test
public void testSkipAttributes() {
- Position position = createPosition(0, new Date(), true, 10, 10, 10, 0, 10);
+ Position position = createPosition(new Date(), true, 0);
position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
- assertNotNull(filteringHandler.handlePosition(position));
+ assertFalse(filteringHandler.filter(position));
}
diff --git a/src/test/java/org/traccar/handler/MotionHandlerTest.java b/src/test/java/org/traccar/handler/MotionHandlerTest.java
index 9e0859664..10cdf6a90 100644
--- a/src/test/java/org/traccar/handler/MotionHandlerTest.java
+++ b/src/test/java/org/traccar/handler/MotionHandlerTest.java
@@ -1,16 +1,30 @@
package org.traccar.handler;
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.model.Device;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class MotionHandlerTest {
@Test
public void testCalculateMotion() {
- MotionHandler motionHandler = new MotionHandler(0.01);
+ var cacheManager = mock(CacheManager.class);
+ when(cacheManager.getObject(eq(Device.class), anyLong())).thenReturn(mock(Device.class));
+ var config = mock(Config.class);
+ when(config.getString(Keys.EVENT_MOTION_SPEED_THRESHOLD.getKey())).thenReturn("0.01");
+ when(cacheManager.getConfig()).thenReturn(config);
+
+ MotionHandler motionHandler = new MotionHandler(cacheManager);
Position position = motionHandler.handlePosition(new Position());
diff --git a/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java b/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java
index 3f0823245..66dc55c85 100644
--- a/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java
+++ b/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java
@@ -1,23 +1,24 @@
package org.traccar.handler.events;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import java.util.Map;
-
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.BaseTest;
-import org.traccar.TestIdentityManager;
import org.traccar.config.Config;
import org.traccar.model.Event;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.mock;
public class AlertEventHandlerTest extends BaseTest {
@Test
public void testAlertEventHandler() {
- AlertEventHandler alertEventHandler = new AlertEventHandler(new Config(), new TestIdentityManager());
+ AlertEventHandler alertEventHandler = new AlertEventHandler(new Config(), mock(CacheManager.class));
Position position = new Position();
position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
@@ -25,6 +26,7 @@ public class AlertEventHandlerTest extends BaseTest {
assertNotNull(events);
Event event = events.keySet().iterator().next();
assertEquals(Event.TYPE_ALARM, event.getType());
+
}
}
diff --git a/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java b/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java
index 0ccf9f6b4..bc24e42f5 100644
--- a/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java
+++ b/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java
@@ -1,15 +1,15 @@
package org.traccar.handler.events;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import java.util.Map;
-
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.BaseTest;
import org.traccar.model.Event;
import org.traccar.model.Position;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
public class CommandResultEventHandlerTest extends BaseTest {
@Test
diff --git a/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java b/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java
index dade20fb8..972932df4 100644
--- a/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java
+++ b/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java
@@ -1,21 +1,22 @@
package org.traccar.handler.events;
-import static org.junit.Assert.assertNull;
-
-import java.util.Map;
-
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.BaseTest;
-import org.traccar.TestIdentityManager;
import org.traccar.model.Event;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.Mockito.mock;
public class IgnitionEventHandlerTest extends BaseTest {
@Test
public void testIgnitionEventHandler() {
- IgnitionEventHandler ignitionEventHandler = new IgnitionEventHandler(new TestIdentityManager());
+ IgnitionEventHandler ignitionEventHandler = new IgnitionEventHandler(mock(CacheManager.class));
Position position = new Position();
position.set(Position.KEY_IGNITION, true);
diff --git a/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java b/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java
new file mode 100644
index 000000000..5320be926
--- /dev/null
+++ b/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java
@@ -0,0 +1,60 @@
+package org.traccar.handler.events;
+
+import org.junit.jupiter.api.Test;
+import org.traccar.BaseTest;
+import org.traccar.model.Maintenance;
+import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+
+import java.util.Arrays;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.anyLong;
+
+public class MaintenanceEventHandlerTest extends BaseTest {
+
+ @Test
+ public void testMaintenanceEventHandler() {
+ Position lastPosition = new Position();
+ lastPosition.setDeviceId(1);
+ lastPosition.setFixTime(new Date(0));
+
+ Position position = new Position();
+ position.setDeviceId(1);
+ position.setFixTime(new Date(0));
+
+ var maintenance = mock(Maintenance.class);
+ when(maintenance.getType()).thenReturn(Position.KEY_TOTAL_DISTANCE);
+ var maintenances = Arrays.asList(maintenance);
+
+ var cacheManager = mock(CacheManager.class);
+ when(cacheManager.getDeviceObjects(anyLong(), eq(Maintenance.class))).thenReturn(maintenances);
+ when(cacheManager.getPosition(anyLong())).thenReturn(lastPosition);
+ MaintenanceEventHandler eventHandler = new MaintenanceEventHandler(cacheManager);
+
+ when(maintenance.getStart()).thenReturn(10000.0);
+ when(maintenance.getPeriod()).thenReturn(2000.0);
+
+ lastPosition.set(Position.KEY_TOTAL_DISTANCE, 1999);
+ position.set(Position.KEY_TOTAL_DISTANCE, 2001);
+ assertTrue(eventHandler.analyzePosition(position).isEmpty());
+
+ lastPosition.set(Position.KEY_TOTAL_DISTANCE, 3999);
+ position.set(Position.KEY_TOTAL_DISTANCE, 4001);
+ assertTrue(eventHandler.analyzePosition(position).isEmpty());
+
+ lastPosition.set(Position.KEY_TOTAL_DISTANCE, 9999);
+ position.set(Position.KEY_TOTAL_DISTANCE, 10001);
+ assertTrue(eventHandler.analyzePosition(position).size() == 1);
+
+ lastPosition.set(Position.KEY_TOTAL_DISTANCE, 11999);
+ position.set(Position.KEY_TOTAL_DISTANCE, 12001);
+ assertTrue(eventHandler.analyzePosition(position).size() == 1);
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java b/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java
index f57c16635..c61ae913d 100644
--- a/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java
+++ b/src/test/java/org/traccar/handler/events/MotionEventHandlerTest.java
@@ -1,119 +1,112 @@
package org.traccar.handler.events;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import org.junit.jupiter.api.Test;
+import org.traccar.BaseTest;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+import org.traccar.reports.common.TripsConfig;
+import org.traccar.session.state.MotionProcessor;
+import org.traccar.session.state.MotionState;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Map;
import java.util.TimeZone;
-import org.junit.Test;
-import org.traccar.BaseTest;
-import org.traccar.model.DeviceState;
-import org.traccar.model.Event;
-import org.traccar.model.Position;
-import org.traccar.reports.model.TripsConfig;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
public class MotionEventHandlerTest extends BaseTest {
- private Date date(String time) throws ParseException {
+ private Position position(String time, boolean motion, double distance, Boolean ignition) throws ParseException {
+ Position position = new Position();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- return dateFormat.parse(time);
+ position.setTime(dateFormat.parse(time));
+ position.set(Position.KEY_MOTION, motion);
+ position.set(Position.KEY_TOTAL_DISTANCE, distance);
+ position.set(Position.KEY_IGNITION, ignition);
+ return position;
+ }
+
+ private void verifyState(MotionState motionState, boolean state, long distance) {
+ assertEquals(state, motionState.getMotionState());
+ assertEquals(distance, motionState.getMotionDistance(), 0.1);
}
@Test
- public void testMotionWithPosition() throws Exception {
- MotionEventHandler motionEventHandler = new MotionEventHandler(
- null, null, new TripsConfig(500, 300 * 1000, 300 * 1000, 0, false, false, 0.01));
+ public void testMotionWithPosition() throws ParseException {
+ TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, false);
- Position position = new Position();
- position.setTime(date("2017-01-01 00:00:00"));
- position.set(Position.KEY_MOTION, true);
- position.set(Position.KEY_TOTAL_DISTANCE, 0);
- DeviceState deviceState = new DeviceState();
- deviceState.setMotionState(false);
- deviceState.setMotionPosition(position);
- Position nextPosition = new Position();
-
- nextPosition.setTime(date("2017-01-01 00:02:00"));
- nextPosition.set(Position.KEY_MOTION, true);
- nextPosition.set(Position.KEY_TOTAL_DISTANCE, 200);
-
- Map<Event, Position> events = motionEventHandler.updateMotionState(deviceState, nextPosition);
- assertNull(events);
-
- nextPosition.set(Position.KEY_TOTAL_DISTANCE, 600);
- events = motionEventHandler.updateMotionState(deviceState, nextPosition);
- assertNotNull(events);
- Event event = events.keySet().iterator().next();
- assertEquals(Event.TYPE_DEVICE_MOVING, event.getType());
- assertTrue(deviceState.getMotionState());
- assertNull(deviceState.getMotionPosition());
-
- deviceState.setMotionState(false);
- deviceState.setMotionPosition(position);
- nextPosition.setTime(date("2017-01-01 00:06:00"));
- nextPosition.set(Position.KEY_TOTAL_DISTANCE, 200);
- events = motionEventHandler.updateMotionState(deviceState, nextPosition);
- assertNotNull(event);
- event = events.keySet().iterator().next();
- assertEquals(Event.TYPE_DEVICE_MOVING, event.getType());
- assertTrue(deviceState.getMotionState());
- assertNull(deviceState.getMotionPosition());
+ MotionState state = new MotionState();
+
+ MotionProcessor.updateState(state, position("2017-01-01 00:00:00", false, 0, null), false, tripsConfig);
+ assertNull(state.getEvent());
+ verifyState(state, false, 0);
+
+ MotionProcessor.updateState(state, position("2017-01-01 00:02:00", true, 100, null), true, tripsConfig);
+ assertNull(state.getEvent());
+ verifyState(state, true, 100);
+
+ MotionProcessor.updateState(state, position("2017-01-01 00:02:00", true, 700, null), true, tripsConfig);
+ assertEquals(Event.TYPE_DEVICE_MOVING, state.getEvent().getType());
+ verifyState(state, true, 0);
+
+ MotionProcessor.updateState(state, position("2017-01-01 00:03:00", false, 700, null), false, tripsConfig);
+ assertNull(state.getEvent());
+ verifyState(state, false, 700);
+
+ MotionProcessor.updateState(state, position("2017-01-01 00:10:00", false, 700, null), false, tripsConfig);
+ assertEquals(Event.TYPE_DEVICE_STOPPED, state.getEvent().getType());
+ verifyState(state, false, 0);
}
@Test
- public void testMotionWithStatus() throws Exception {
- MotionEventHandler motionEventHandler = new MotionEventHandler(
- null, null, new TripsConfig(500, 300 * 1000, 300 * 1000, 0, false, false, 0.01));
+ public void testMotionFluctuation() throws ParseException {
+ TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, false);
- Position position = new Position();
- position.setTime(new Date(System.currentTimeMillis() - 360000));
- position.set(Position.KEY_MOTION, true);
- DeviceState deviceState = new DeviceState();
- deviceState.setMotionState(false);
- deviceState.setMotionPosition(position);
-
- Map<Event, Position> events = motionEventHandler.updateMotionState(deviceState);
-
- assertNotNull(events);
- Event event = events.keySet().iterator().next();
- assertEquals(Event.TYPE_DEVICE_MOVING, event.getType());
- assertTrue(deviceState.getMotionState());
- assertNull(deviceState.getMotionPosition());
+ MotionState state = new MotionState();
+
+ MotionProcessor.updateState(state, position("2017-01-01 00:00:00", false, 0, null), false, tripsConfig);
+ assertNull(state.getEvent());
+ verifyState(state, false, 0);
+
+ MotionProcessor.updateState(state, position("2017-01-01 00:02:00", true, 100, null), true, tripsConfig);
+ assertNull(state.getEvent());
+ verifyState(state, true, 100);
+
+ MotionProcessor.updateState(state, position("2017-01-01 00:02:00", true, 700, null), true, tripsConfig);
+ assertEquals(Event.TYPE_DEVICE_MOVING, state.getEvent().getType());
+ verifyState(state, true, 0);
+
+ MotionProcessor.updateState(state, position("2017-01-01 00:03:00", false, 700, null), false, tripsConfig);
+ assertNull(state.getEvent());
+ verifyState(state, false, 700);
+
+ MotionProcessor.updateState(state, position("2017-01-01 00:04:00", true, 1000, null), true, tripsConfig);
+ assertNull(state.getEvent());
+ verifyState(state, true, 0);
+
+ MotionProcessor.updateState(state, position("2017-01-01 00:06:00", true, 2000, null), true, tripsConfig);
+ assertNull(state.getEvent());
+ verifyState(state, true, 0);
}
@Test
- public void testStopWithPositionIgnition() throws Exception {
- MotionEventHandler motionEventHandler = new MotionEventHandler(
- null, null, new TripsConfig(500, 300 * 1000, 300 * 1000, 0, true, false, 0.01));
+ public void testStopWithPositionIgnition() throws ParseException {
+ TripsConfig tripsConfig = new TripsConfig(500, 300000, 300000, 0, true);
- Position position = new Position();
- position.setTime(date("2017-01-01 00:00:00"));
- position.set(Position.KEY_MOTION, false);
- position.set(Position.KEY_IGNITION, true);
- DeviceState deviceState = new DeviceState();
- deviceState.setMotionState(true);
- deviceState.setMotionPosition(position);
-
- Position nextPosition = new Position();
- nextPosition.setTime(date("2017-01-01 00:02:00"));
- nextPosition.set(Position.KEY_MOTION, false);
- nextPosition.set(Position.KEY_IGNITION, false);
-
- Map<Event, Position> events = motionEventHandler.updateMotionState(deviceState, nextPosition);
- assertNotNull(events);
- Event event = events.keySet().iterator().next();
- assertEquals(Event.TYPE_DEVICE_STOPPED, event.getType());
- assertFalse(deviceState.getMotionState());
- assertNull(deviceState.getMotionPosition());
+ MotionState state = new MotionState();
+ state.setMotionStreak(true);
+ state.setMotionState(true);
+
+ MotionProcessor.updateState(state, position("2017-01-01 00:00:00", false, 100, true), false, tripsConfig);
+ assertNull(state.getEvent());
+ verifyState(state, false, 100);
+
+ MotionProcessor.updateState(state, position("2017-01-01 00:02:00", false, 100, false), false, tripsConfig);
+ assertEquals(Event.TYPE_DEVICE_STOPPED, state.getEvent().getType());
+ verifyState(state, false, 0);
}
}
diff --git a/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java b/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java
index 515f37b5d..97d929551 100644
--- a/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java
+++ b/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java
@@ -1,128 +1,68 @@
package org.traccar.handler.events;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
+import org.junit.jupiter.api.Test;
+import org.traccar.BaseTest;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+import org.traccar.session.state.OverspeedProcessor;
+import org.traccar.session.state.OverspeedState;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Map;
import java.util.TimeZone;
-import org.junit.Test;
-import org.traccar.BaseTest;
-import org.traccar.config.Config;
-import org.traccar.config.Keys;
-import org.traccar.model.DeviceState;
-import org.traccar.model.Event;
-import org.traccar.model.Position;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
public class OverspeedEventHandlerTest extends BaseTest {
- private Date date(String time) throws ParseException {
+ private Position position(String time, double speed) throws ParseException {
+ Position position = new Position();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- return dateFormat.parse(time);
+ position.setTime(dateFormat.parse(time));
+ position.setSpeed(speed);
+ return position;
}
- private void testOverspeedWithPosition(boolean notRepeat, long geofenceId) throws ParseException {
- Config config = new Config();
- config.setString(Keys.EVENT_OVERSPEED_NOT_REPEAT, String.valueOf(notRepeat));
- config.setString(Keys.EVENT_OVERSPEED_MINIMAL_DURATION, String.valueOf(15));
- config.setString(Keys.EVENT_OVERSPEED_PREFER_LOWEST, String.valueOf(false));
- OverspeedEventHandler overspeedEventHandler = new OverspeedEventHandler(config, null, null);
-
- Position position = new Position();
- position.setTime(date("2017-01-01 00:00:00"));
- position.setSpeed(50);
- DeviceState deviceState = new DeviceState();
- deviceState.setOverspeedState(false);
-
- Map<Event, Position> events = overspeedEventHandler.updateOverspeedState(deviceState, position, 40, geofenceId);
- assertNull(events);
- assertFalse(deviceState.getOverspeedState());
- assertEquals(position, deviceState.getOverspeedPosition());
- assertEquals(geofenceId, deviceState.getOverspeedGeofenceId());
-
- Position nextPosition = new Position();
- nextPosition.setTime(date("2017-01-01 00:00:10"));
- nextPosition.setSpeed(55);
-
- events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40, geofenceId);
- assertNull(events);
-
- nextPosition.setTime(date("2017-01-01 00:00:20"));
-
- events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40, geofenceId);
- assertNotNull(events);
- Event event = events.keySet().iterator().next();
- assertEquals(Event.TYPE_DEVICE_OVERSPEED, event.getType());
- assertEquals(50, event.getDouble("speed"), 0.1);
- assertEquals(40, event.getDouble(OverspeedEventHandler.ATTRIBUTE_SPEED_LIMIT), 0.1);
- assertEquals(geofenceId, event.getGeofenceId());
-
- assertEquals(notRepeat, deviceState.getOverspeedState());
- assertNull(deviceState.getOverspeedPosition());
- assertEquals(0, deviceState.getOverspeedGeofenceId());
-
- nextPosition.setTime(date("2017-01-01 00:00:30"));
- events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40, geofenceId);
- assertNull(events);
- assertEquals(notRepeat, deviceState.getOverspeedState());
+ private void verifyState(OverspeedState overspeedState, boolean state, long geofenceId) {
+ assertEquals(state, overspeedState.getOverspeedState());
+ assertEquals(geofenceId, overspeedState.getOverspeedGeofenceId());
+ }
- if (notRepeat) {
- assertNull(deviceState.getOverspeedPosition());
- assertEquals(0, deviceState.getOverspeedGeofenceId());
- } else {
- assertNotNull(deviceState.getOverspeedPosition());
- assertEquals(geofenceId, deviceState.getOverspeedGeofenceId());
- }
+ private void testOverspeedWithPosition(long geofenceId) throws ParseException {
+ OverspeedState state = new OverspeedState();
- nextPosition.setTime(date("2017-01-01 00:00:40"));
- nextPosition.setSpeed(30);
+ OverspeedProcessor.updateState(state, position("2017-01-01 00:00:00", 50), 40, 1, 15000, geofenceId);
+ assertNull(state.getEvent());
+ verifyState(state, true, geofenceId);
- events = overspeedEventHandler.updateOverspeedState(deviceState, nextPosition, 40, geofenceId);
- assertNull(events);
- assertFalse(deviceState.getOverspeedState());
- assertNull(deviceState.getOverspeedPosition());
- assertEquals(0, deviceState.getOverspeedGeofenceId());
- }
+ OverspeedProcessor.updateState(state, position("2017-01-01 00:00:10", 55), 40, 1, 15000, geofenceId);
+ assertNull(state.getEvent());
- private void testOverspeedWithStatus(boolean notRepeat) {
- Config config = new Config();
- config.setString(Keys.EVENT_OVERSPEED_NOT_REPEAT, String.valueOf(notRepeat));
- config.setString(Keys.EVENT_OVERSPEED_MINIMAL_DURATION, String.valueOf(15));
- config.setString(Keys.EVENT_OVERSPEED_PREFER_LOWEST, String.valueOf(false));
- OverspeedEventHandler overspeedEventHandler = new OverspeedEventHandler(config, null, null);
+ OverspeedProcessor.updateState(state, position("2017-01-01 00:00:20", 55), 40, 1, 15000, geofenceId);
+ assertNotNull(state.getEvent());
+ assertEquals(Event.TYPE_DEVICE_OVERSPEED, state.getEvent().getType());
+ assertEquals(55, state.getEvent().getDouble("speed"), 0.1);
+ assertEquals(40, state.getEvent().getDouble("speedLimit"), 0.1);
+ assertEquals(geofenceId, state.getEvent().getGeofenceId());
+ verifyState(state, true, 0);
- Position position = new Position();
- position.setTime(new Date(System.currentTimeMillis() - 30000));
- position.setSpeed(50);
- DeviceState deviceState = new DeviceState();
- deviceState.setOverspeedState(false);
- deviceState.setOverspeedPosition(position);
+ OverspeedProcessor.updateState(state, position("2017-01-01 00:00:30", 55), 40, 1, 15000, geofenceId);
+ assertNull(state.getEvent());
+ verifyState(state, true, 0);
- Map<Event, Position> events = overspeedEventHandler.updateOverspeedState(deviceState, 40);
-
- assertNotNull(events);
- Event event = events.keySet().iterator().next();
- assertEquals(Event.TYPE_DEVICE_OVERSPEED, event.getType());
- assertEquals(notRepeat, deviceState.getOverspeedState());
+ OverspeedProcessor.updateState(state, position("2017-01-01 00:00:30", 30), 40, 1, 15000, geofenceId);
+ assertNull(state.getEvent());
+ verifyState(state, false, 0);
}
@Test
public void testOverspeedEventHandler() throws Exception {
- testOverspeedWithPosition(false, 0);
- testOverspeedWithPosition(true, 0);
-
- testOverspeedWithPosition(false, 1);
- testOverspeedWithPosition(true, 1);
-
- testOverspeedWithStatus(false);
- testOverspeedWithStatus(true);
+ testOverspeedWithPosition(0);
+ testOverspeedWithPosition(1);
}
}
diff --git a/src/test/java/org/traccar/helper/BcdUtilTest.java b/src/test/java/org/traccar/helper/BcdUtilTest.java
index 86a32f725..440cd90d4 100644
--- a/src/test/java/org/traccar/helper/BcdUtilTest.java
+++ b/src/test/java/org/traccar/helper/BcdUtilTest.java
@@ -1,9 +1,9 @@
package org.traccar.helper;
import io.netty.buffer.Unpooled;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class BcdUtilTest {
diff --git a/src/test/java/org/traccar/helper/BitBufferTest.java b/src/test/java/org/traccar/helper/BitBufferTest.java
index c2abad36d..3b3521213 100644
--- a/src/test/java/org/traccar/helper/BitBufferTest.java
+++ b/src/test/java/org/traccar/helper/BitBufferTest.java
@@ -1,8 +1,8 @@
package org.traccar.helper;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class BitBufferTest {
diff --git a/src/test/java/org/traccar/helper/BitUtilTest.java b/src/test/java/org/traccar/helper/BitUtilTest.java
index 90431bf55..803c327bc 100644
--- a/src/test/java/org/traccar/helper/BitUtilTest.java
+++ b/src/test/java/org/traccar/helper/BitUtilTest.java
@@ -1,10 +1,10 @@
package org.traccar.helper;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class BitUtilTest {
diff --git a/src/test/java/org/traccar/helper/BufferUtilTest.java b/src/test/java/org/traccar/helper/BufferUtilTest.java
index b539b5b28..707e419ec 100644
--- a/src/test/java/org/traccar/helper/BufferUtilTest.java
+++ b/src/test/java/org/traccar/helper/BufferUtilTest.java
@@ -2,15 +2,21 @@ package org.traccar.helper;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import java.nio.charset.StandardCharsets;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class BufferUtilTest {
@Test
+ public void testReadSignedMagnitudeInt() {
+ ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex("80000001"));
+ assertEquals(-1, BufferUtil.readSignedMagnitudeInt(buf));
+ }
+
+ @Test
public void test1() {
ByteBuf buf = Unpooled.copiedBuffer("abcdef", StandardCharsets.US_ASCII);
assertEquals(2, BufferUtil.indexOf("cd", buf));
diff --git a/src/test/java/org/traccar/helper/ChecksumTest.java b/src/test/java/org/traccar/helper/ChecksumTest.java
index 248f4dcae..51f62aba0 100644
--- a/src/test/java/org/traccar/helper/ChecksumTest.java
+++ b/src/test/java/org/traccar/helper/ChecksumTest.java
@@ -2,12 +2,12 @@ package org.traccar.helper;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class ChecksumTest {
diff --git a/src/test/java/org/traccar/helper/DateBuilderTest.java b/src/test/java/org/traccar/helper/DateBuilderTest.java
index b6323cc1d..35797a3ef 100644
--- a/src/test/java/org/traccar/helper/DateBuilderTest.java
+++ b/src/test/java/org/traccar/helper/DateBuilderTest.java
@@ -1,13 +1,13 @@
package org.traccar.helper;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class DateBuilderTest {
diff --git a/src/test/java/org/traccar/helper/DateUtilTest.java b/src/test/java/org/traccar/helper/DateUtilTest.java
index ec42e71ae..b5a4b1eab 100644
--- a/src/test/java/org/traccar/helper/DateUtilTest.java
+++ b/src/test/java/org/traccar/helper/DateUtilTest.java
@@ -1,13 +1,13 @@
package org.traccar.helper;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class DateUtilTest {
diff --git a/src/test/java/org/traccar/helper/DistanceCalculatorTest.java b/src/test/java/org/traccar/helper/DistanceCalculatorTest.java
index a7457b6c4..676fda5ea 100644
--- a/src/test/java/org/traccar/helper/DistanceCalculatorTest.java
+++ b/src/test/java/org/traccar/helper/DistanceCalculatorTest.java
@@ -1,8 +1,8 @@
package org.traccar.helper;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class DistanceCalculatorTest {
diff --git a/src/test/java/org/traccar/helper/LogTest.java b/src/test/java/org/traccar/helper/LogTest.java
index ef33c32ba..a264896b5 100644
--- a/src/test/java/org/traccar/helper/LogTest.java
+++ b/src/test/java/org/traccar/helper/LogTest.java
@@ -1,8 +1,8 @@
package org.traccar.helper;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class LogTest {
diff --git a/src/test/java/org/traccar/helper/ObdDecoderTest.java b/src/test/java/org/traccar/helper/ObdDecoderTest.java
index d5071bd51..2233ab5b3 100644
--- a/src/test/java/org/traccar/helper/ObdDecoderTest.java
+++ b/src/test/java/org/traccar/helper/ObdDecoderTest.java
@@ -1,8 +1,8 @@
package org.traccar.helper;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class ObdDecoderTest {
diff --git a/src/test/java/org/traccar/helper/PatternBuilderTest.java b/src/test/java/org/traccar/helper/PatternBuilderTest.java
index 4c76bc463..a8657a2e7 100644
--- a/src/test/java/org/traccar/helper/PatternBuilderTest.java
+++ b/src/test/java/org/traccar/helper/PatternBuilderTest.java
@@ -1,8 +1,8 @@
package org.traccar.helper;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class PatternBuilderTest {
diff --git a/src/test/java/org/traccar/helper/PatternUtilTest.java b/src/test/java/org/traccar/helper/PatternUtilTest.java
index 77660078a..ff8efe773 100644
--- a/src/test/java/org/traccar/helper/PatternUtilTest.java
+++ b/src/test/java/org/traccar/helper/PatternUtilTest.java
@@ -1,13 +1,13 @@
package org.traccar.helper;
-import org.junit.Ignore;
-import org.junit.Test;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class PatternUtilTest {
- @Ignore
+ @Disabled
@Test
public void testCheckPattern() {
diff --git a/src/test/java/org/traccar/helper/ServletHelperTest.java b/src/test/java/org/traccar/helper/ServletHelperTest.java
deleted file mode 100644
index e419b6491..000000000
--- a/src/test/java/org/traccar/helper/ServletHelperTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.traccar.helper;
-
-import org.apache.struts.mock.MockHttpServletRequest;
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-
-public class ServletHelperTest {
-
- @Test
- public void testRetrieveRemoteAddressProxyMultiple() {
- MockRequest request = new MockRequest();
- request.setRemoteAddress("147.120.1.5");
- request.addHeader("X-FORWARDED-FOR", "231.23.45.65, 10.20.10.33, 10.20.20.34");
-
- assertEquals("231.23.45.65", ServletHelper.retrieveRemoteAddress(request));
- }
-
- @Test
- public void testRetrieveRemoteAddressProxySingle() {
- MockRequest request = new MockRequest();
- request.setRemoteAddress("147.120.1.5");
- request.addHeader("X-FORWARDED-FOR", "231.23.45.65");
-
- assertEquals("231.23.45.65", ServletHelper.retrieveRemoteAddress(request));
- }
-
- @Test
- public void testRetrieveRemoteAddressNoProxy() {
- MockRequest request = new MockRequest();
- request.setRemoteAddress("231.23.45.65");
-
- assertEquals("231.23.45.65", ServletHelper.retrieveRemoteAddress(request));
- }
-
- private final static class MockRequest extends MockHttpServletRequest {
-
- private String remoteAddress;
-
- private Map<String, String> headers = new HashMap<>();
-
- public void setRemoteAddress(String remoteAddress) {
- this.remoteAddress = remoteAddress;
- }
-
- public void addHeader(String name, String value) {
- headers.put(name, value);
- }
-
- @Override
- public String getHeader(String name) {
- return headers.get(name);
- }
-
- @Override
- public String getRemoteAddr() {
- return remoteAddress;
- }
-
- }
-
-}
diff --git a/src/test/java/org/traccar/helper/WebHelperTest.java b/src/test/java/org/traccar/helper/WebHelperTest.java
new file mode 100644
index 000000000..da18be11e
--- /dev/null
+++ b/src/test/java/org/traccar/helper/WebHelperTest.java
@@ -0,0 +1,39 @@
+package org.traccar.helper;
+
+import org.junit.jupiter.api.Test;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class WebHelperTest {
+
+ @Test
+ public void testRetrieveRemoteAddressProxyMultiple() {
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ when(request.getRemoteAddr()).thenReturn("147.120.1.5");
+ when(request.getHeader("X-FORWARDED-FOR")).thenReturn("231.23.45.65, 10.20.10.33, 10.20.20.34");
+
+ assertEquals("231.23.45.65", WebHelper.retrieveRemoteAddress(request));
+ }
+
+ @Test
+ public void testRetrieveRemoteAddressProxySingle() {
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ when(request.getRemoteAddr()).thenReturn("147.120.1.5");
+ when(request.getHeader("X-FORWARDED-FOR")).thenReturn("231.23.45.65");
+
+ assertEquals("231.23.45.65", WebHelper.retrieveRemoteAddress(request));
+ }
+
+ @Test
+ public void testRetrieveRemoteAddressNoProxy() {
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ when(request.getRemoteAddr()).thenReturn("231.23.45.65");
+
+ assertEquals("231.23.45.65", WebHelper.retrieveRemoteAddress(request));
+ }
+
+}
diff --git a/src/test/java/org/traccar/notification/NotificiationMailTest.java b/src/test/java/org/traccar/notification/NotificiationMailTest.java
index b82bec02e..ccc8cc47d 100644
--- a/src/test/java/org/traccar/notification/NotificiationMailTest.java
+++ b/src/test/java/org/traccar/notification/NotificiationMailTest.java
@@ -1,13 +1,13 @@
package org.traccar.notification;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import javax.mail.Message;
-import javax.mail.Session;
-import javax.mail.Transport;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import jakarta.mail.Message;
+import jakarta.mail.Session;
+import jakarta.mail.Transport;
+import jakarta.mail.internet.InternetAddress;
+import jakarta.mail.internet.MimeMessage;
import java.util.Properties;
public class NotificiationMailTest {
@@ -25,7 +25,7 @@ public class NotificiationMailTest {
private static final int PORT = 25;
- @Ignore
+ @Disabled
@Test
public void test() throws Exception {
diff --git a/src/test/java/org/traccar/protocol/AdmFrameDecoderTest.java b/src/test/java/org/traccar/protocol/AdmFrameDecoderTest.java
index 1682ca56d..bd50e1d14 100644
--- a/src/test/java/org/traccar/protocol/AdmFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AdmFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AdmFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AdmFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AdmFrameDecoder();
+ var decoder = inject(new AdmFrameDecoder());
verifyFrame(
binary("38363931353330343235323337383400003728e000001402441d5f42c3711642930d000000c7000a461954f25fd82ed508000000000000000044000000010000000000140000"),
diff --git a/src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java
index 7c8769925..f09a42ba8 100644
--- a/src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AdmProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AdmProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AdmProtocolDecoder(null);
+ var decoder = inject(new AdmProtocolDecoder(null));
verifyPosition(decoder, binary(
"38363931353330343235323337383400003728e000001402441d5f42c3711642930d000000c7000a461954f25fd82ed508000000000000000044000000010000000000140000"));
diff --git a/src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java
index 89ddef849..26f59015d 100644
--- a/src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java
@@ -16,18 +16,18 @@
*/
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class AdmProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new AdmProtocolEncoder(null);
+ var encoder = inject(new AdmProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java
index f869ab8f3..b322bbbc7 100644
--- a/src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AisProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AisProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AisProtocolDecoder(null);
+ var decoder = inject(new AisProtocolDecoder(null));
verifyPositions(decoder, text(
"!AIVDM,2,1,8,A,53UlSb01l>Ei=H4KF218PTpv222222222222221?8h=766gB0<Ck11DTp888,0*14s:MTb827ebc7686b,c:1481688227737*4d\\\r\n" +
diff --git a/src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java
index 8bd457a97..84108160a 100644
--- a/src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AlematicsProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AlematicsProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AlematicsProtocolDecoder(null);
+ var decoder = inject(new AlematicsProtocolDecoder(null));
verifyPosition(decoder, text(
"$T,2,64,866050035975497,20180726103446,20180726103514,23.033305,72.558032,0,0,41,5.4,4,0,0,0.000,12.960,0,"));
diff --git a/src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java
index b6f95513c..aec26c0c1 100644
--- a/src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AnytrekProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AnytrekProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AnytrekProtocolDecoder(null);
+ var decoder = inject(new AnytrekProtocolDecoder(null));
verifyPosition(decoder, binary(
"78783500300086428703204121160085015111050C0A0D20C6FD24A102FF8EAC0C01001404000000FFFFFFFF131702210000000000000000000D0A"));
diff --git a/src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java
index b922d3ef1..6aef8409b 100644
--- a/src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class ApelProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class ApelProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new ApelProtocolDecoder(null);
+ var decoder = inject(new ApelProtocolDecoder(null));
/*byte[] buf1 = {0x40,0x4E,0x54,0x43,0x01,0x00,0x00,0x00,0x7B,0x00,0x00,0x00,0x13,0x00,0x44,0x34,0x2A,0x3E,0x53,0x3A,0x38,0x36,0x31,0x37,0x38,0x35,0x30,0x30,0x35,0x32,0x30,0x35,0x30,0x37,0x39};
verifyNull(decoder, text( ChannelBuffers.wrappedBuffer(ByteOrder.LITTLE_ENDIAN, buf1)));*/
diff --git a/src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java b/src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java
index 96a219d2a..316e897a7 100644
--- a/src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java
@@ -1,16 +1,16 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class AplicomFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AplicomFrameDecoder();
+ var decoder = inject(new AplicomFrameDecoder());
assertEquals(
binary("44C20146B710C158DA009500B09F7700C054CA0EA454CA0EA403BE0BF6015D706B070000142A600000000000000002434946010801000754CA0EA4000000000000008400000000000000000000000000000000300000FE00FE0000000000000000000000000000000000000000000000000000000000000000000040502035000000000000020D0000030D0000040C0000040D0000050C0000050D0000058C0000060C"),
diff --git a/src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java
index 5abe9550d..b4b5da0ce 100644
--- a/src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AplicomProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AplicomProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AplicomProtocolDecoder(null);
+ var decoder = inject(new AplicomProtocolDecoder(null));
verifyNull(decoder, binary(
"434946010A0100075253F85F0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FEEA0000FEE90000F0030000F0040000FEF10000FEF20000FEF50000FEFC0000FEC10000FEE500"));
diff --git a/src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java
index da4d82938..d0dd368e7 100644
--- a/src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AppelloProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AppelloProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AppelloProtocolDecoder(null);
+ var decoder = inject(new AppelloProtocolDecoder(null));
verifyAttributes(decoder, text(
"FOLLOWIT,867273024233699,UTCTIME,0.000000,0.000000,0,0,0,0,L,262:3:c703:4bf8:64:255|262:3:c703:9a18:45|262:3:c703:e838:33|262:3:c703:7190:20|262:3:c704:d896:17|,02,44,,31,,4.20,0,0,86/44/24,,,,26,02264DFF6E16:69|4C09D408554E:79|4C09D408554F:79|E0885DE705E5:81|E2885DE705E7:81|246511122CCC:83|,34925"));
diff --git a/src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java
index 57d793c71..fa9cc9851 100644
--- a/src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AquilaProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AquilaProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecodeA() throws Exception {
- var decoder = new AquilaProtocolDecoder(null);
+ var decoder = inject(new AquilaProtocolDecoder(null));
verifyPosition(decoder, text(
"$$CLIENT_1ZF,170215089,20,18.462809,73.824188,170613182744,A,01,123456,*37"));
diff --git a/src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java
index 653e4346d..9f567c87b 100644
--- a/src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Ardi01ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Ardi01ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Ardi01ProtocolDecoder(null);
+ var decoder = inject(new Ardi01ProtocolDecoder(null));
verifyPosition(decoder, text(
"013227003054776,20141010052719,24.4736042,56.8445807,110,289,40,7,5,78,-1"),
diff --git a/src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java
index b95963f40..e3a2658a8 100644
--- a/src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class ArknavProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class ArknavProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new ArknavProtocolDecoder(null);
+ var decoder = inject(new ArknavProtocolDecoder(null));
verifyPosition(decoder, text(
"358266016278447,05*827,000,L001,V,4821.6584,N,01053.8650,E,000.0,000.0,00.0,08:46:04 17-03-16,9.5A,D7,0,79,0,,,,"),
diff --git a/src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java
index c2d78dca6..c81ef1684 100644
--- a/src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class ArknavX8ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class ArknavX8ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new ArknavX8ProtocolDecoder(null);
+ var decoder = inject(new ArknavX8ProtocolDecoder(null));
verifyNull(decoder, text(
"351856045213782,241111"));
diff --git a/src/test/java/org/traccar/protocol/ArmoliProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArmoliProtocolDecoderTest.java
index da2542b34..42e1ab477 100644
--- a/src/test/java/org/traccar/protocol/ArmoliProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ArmoliProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class ArmoliProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new ArmoliProtocolDecoder(null);
+ var decoder = inject(new ArmoliProtocolDecoder(null));
verifyAttribute(decoder, text(
"[M869867039550712160821153237N41.033508E029.2697032F00036000000410006B336FFFFG458563@A6D>04410C2482>03410F56>03412F19>0441210000>034130FF>0441313A7>03410D30>04411F01B6>0341048C>04410C1C98];"),
diff --git a/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java
index f2940de59..e38e63755 100644
--- a/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class ArnaviBinaryProtocolDecoderTest extends ProtocolTest {
@@ -8,9 +8,7 @@ public class ArnaviBinaryProtocolDecoderTest extends ProtocolTest {
@Test
public void testHeader1Decode() throws Exception {
- ArnaviBinaryProtocolDecoder decoder;
-
- decoder = new ArnaviBinaryProtocolDecoder(null);
+ var decoder = inject(new ArnaviBinaryProtocolDecoder(null));
verifyNull(decoder, binary(
"ff22f30c45f5c90f0300"));
@@ -23,9 +21,7 @@ public class ArnaviBinaryProtocolDecoderTest extends ProtocolTest {
@Test
public void testHeader2Decode() throws Exception {
- ArnaviBinaryProtocolDecoder decoder;
-
- decoder = new ArnaviBinaryProtocolDecoder(null);
+ var decoder = inject(new ArnaviBinaryProtocolDecoder(null));
verifyNull(decoder, binary(
"ff23f30c45f5c90f0300"));
diff --git a/src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java b/src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java
index 3f495731a..4997e535d 100644
--- a/src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class ArnaviFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class ArnaviFrameDecoderTest extends ProtocolTest {
@Test
public void testDecodeValidPackets() throws Exception {
- var decoder = new ArnaviFrameDecoder();
+ var decoder = inject(new ArnaviFrameDecoder());
verifyFrame(
binary("2441562c563344492c38353136342c3231342c2d312c31392c30303030344634462c30303030303935452c30433030303030322c3836333037313031333034313631382c38393939373031353630333832353236363232462c2a3039"),
diff --git a/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java
index 9e9047be4..ed9fd0cfe 100644
--- a/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class ArnaviTextProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class ArnaviTextProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new ArnaviTextProtocolDecoder(null);
+ var decoder = inject(new ArnaviTextProtocolDecoder(null));
verifyPosition(decoder, buffer(
"$AV,V4,999999,12487,2277,203,65534,0,0,193,65535,65535,65535,65535,1,13,80.0,56.1,200741,5950.6773N,03029.1043E,300.0,360.0,121012,65535,65535,65535,SF*6E"));
diff --git a/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java
index 3376fa3f0..3dabcac5d 100644
--- a/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AstraProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AstraProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AstraProtocolDecoder(null);
+ var decoder = inject(new AstraProtocolDecoder(null));
verifyPositions(decoder, binary(
"4b00700529c0c265976b8202cba9ff00676d864554a9c30000000020073401006436000300030008000000000000a0000100001920c43d00009600428302cba9ff00676d864554aa3e000000002007240100643b000300020008000000000000b0000100001920c43d00009600420f0e"));
diff --git a/src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java b/src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java
index 0782c2d34..c83a5fd4e 100644
--- a/src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class At2000FrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class At2000FrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new At2000FrameDecoder();
+ var decoder = inject(new At2000FrameDecoder());
verifyFrame(
binary("01012f00000000000000000000000000003335363137333036343430373439320fad981997ae8e031fe10c0ea7641903ca32c0331df467233d2a9cd886fbeef8"),
diff --git a/src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java
index 9e2f180d2..718542e97 100644
--- a/src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java
@@ -1,9 +1,9 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assume.assumeTrue;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
public class At2000ProtocolDecoderTest extends ProtocolTest {
@@ -14,7 +14,7 @@ public class At2000ProtocolDecoderTest extends ProtocolTest {
At2000ProtocolDecoder decoder;
- decoder = new At2000ProtocolDecoder(null);
+ decoder = inject(new At2000ProtocolDecoder(null));
verifyNull(decoder, binary(
"01012f00000000000000000000000000003335373435343037313632373539388b57ec3a6ec7e3310a1ceb0a70fd751b8f2e7be6df1d6dcd80129f66fff0ea1c"));
@@ -22,7 +22,7 @@ public class At2000ProtocolDecoderTest extends ProtocolTest {
verifyNull(decoder, binary(
"89000000000000000000000000000000"));
- decoder = new At2000ProtocolDecoder(null);
+ decoder = inject(new At2000ProtocolDecoder(null));
verifyNull(decoder, binary(
"01012f0000000000000000000000000000333537343534303731363036313936ddf189075add9a32d97b54073025963e65849a3a59940d05fd8db655fc84bc6d"));
@@ -30,7 +30,7 @@ public class At2000ProtocolDecoderTest extends ProtocolTest {
verifyPositions(decoder, binary(
"893b01000000000000000000000000003b40bcdab6387d829146701d8cb53daaa87b84d24b40cb24fd86da5d3f5f02b0f6f603c43c5a513418a0b2bdcaba603dbe737687cfe9082c57668eb6789d2b029a35aeac6a609558b96de5d7ad37917c902efc878ca9aff474f9d5d2417191285b8d5749bd3ffa86cc99096ce24c1f6ac350ae9adf3d5c788f80b4e3d3dc2dbb8abc1414ea1b52fdb55b2bb8af223ec528245f99d451b715e5774c5397db645d9ae441e645f8dae70230b728e81f51240868712d6f426fd694dbad8026fcf487c268939f04593ad86391cc829b1a1bdac8804ff7507544a69dc0b1b3927d7344e8a5b26fa56825283b3e476330b36d15011e1647ebd9f2ef71844ed32c0dc050457bfbd79160e6d1d8cda00a0927c8957631770e98eb20735aa46b0b18502baf4c45d2623ee51a4320cf3018010e7bbf8bc0dd79eb28e88b727ea67e980b8a91"));
- decoder = new At2000ProtocolDecoder(null);
+ decoder = inject(new At2000ProtocolDecoder(null));
verifyNull(decoder, binary(
"01012f000000000000000000000000000033353734353430373136303631393637f5441a9862260117858237fe3160388490f0df7d46c09112ee087235a92101"));
@@ -38,7 +38,7 @@ public class At2000ProtocolDecoderTest extends ProtocolTest {
verifyPositions(decoder, binary(
"89043203000000000000000000000000d01ff1df1b56ba9185bb741ddc253f3cee093b1f8193100cd95777b5288a6f29d1b343a952f882ce8825679f7e27ad88ed7898bff92f716acadfc3c17fa8c1a6b9d0934e8f042433a183776c06c1acd73efb4b9f19030debb4dceb161fb3e6630757d25c3e995b7cf5f446318dcc1677eb215d1af49f11cd7300598bcdc40cc25466ed2391d836c782e44bc04a332e902b2b34f5597a542af4ca670cdfc18d87ce2a225c3e6f2f32359d4914c6df09aa5ee306c229260d4a56da53f93398bc8a6e77095305ee214cf605de20d3876a993fb810486f75bcd514c12442bf4dc3fbe7963b20d5100b5ecff1c1aef4c4b3736a04e245d50f538327db21d55270b279db5ac5a9658876bae3d9b5026b8975bb2bf4d100b8492760d66ae31f27bf9c525c2d794860eabca9c788b91152dbce79f336daaf6a7a9547bf1dd8e3334c891f4548fd6d112ebf45125c2a8abd3a786ebbcfdd03101b524bbf465f14a9a424305ce7de56ffca85b4657fc8c03e4349c0ca6be64d1cf595ee91f8173678ef2267dae54dd00028450c48d9b74c925af0f245d409d8773238dce5832747587f53a12155869c1d464eb0630f94cf8dceb76aa39995411d4ce7743b1501692425afec498535526067e79f568b7f71ee47d8b4929118d57b13d56cdbfd26582d579dee"));
- decoder = new At2000ProtocolDecoder(null);
+ decoder = inject(new At2000ProtocolDecoder(null));
verifyNull(decoder, binary(
"01012f0000000000000000000000000000333537343534303731363035353033dd529a1eb5df9f3b6d320b38250e03306692957e8c2127d8e381a717f639b4c9"));
@@ -46,7 +46,7 @@ public class At2000ProtocolDecoderTest extends ProtocolTest {
verifyPositions(decoder, binary(
"89898701000000000000000000000000ae99e38f13d44f536769eb4930a6826dfebe5b98a6048941e89b17c9cdcb276be4af7c0d188d07c90d6e94aa9efcb465fe7aeaff4d85caf837483b4e9b32fbbacfbc4e175eebf57a27f552a64fc3419565d2dfbea668511a08d5a526342fad0e93b20c4449ad8defab4a9ac68cf7dad86971eb2cd96810d9d6a9c56e07fd90e4c28cfc53a069b63efe37a0523a69b607a2dc011ba17b177c5332c04be1faeeabed24539b3b790fa8a8610ab3633e0140ed79690fcae9dea43c7daad780d95a511d8f4875e621bcfe7516a03b80eb3c473ffd4bc1eda298dfa7d994a2cfeaa5d24c190d52d72fd90975a2e6f9ed3b95017133952262f91787c46839738a80c333dc53ee4d8afe75315d801efe17bc7309f30cfce64906bf70e6844c835781cbb64b49e9315ca3c2cd39d00a03cc7178a4ebc5df230dcdfd44ec588791d488f96bb6ff4007a753f552bda4d1766632aa3ec5eb38feb23ed6efb8f382a7f22b70adc9cb533c09bf749190c36d63b572c1acfc3a59138d51273835ab13c4689df01e3d2c2dd1829e00aac5c56b5d51e60d6731833f82c7464d88df663ca28a20eedeecb60f3704ae78281838caa116184e414db459768321bbfa1e83ad59fe168eb81f3b41cfe0e39c8aa78cbbe5825620bf053a1cb62e04d4cdf17ca2dc9305d47c"));
- decoder = new At2000ProtocolDecoder(null);
+ decoder = inject(new At2000ProtocolDecoder(null));
verifyNull(decoder, binary(
"01012f00000000000000000000000000003335363137333036343430373439320fad981997ae8e031fe10c0ea7641903ca32c0331df467233d2a9cd886fbeef8"));
diff --git a/src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java b/src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java
index 77e90ca53..7b2334919 100644
--- a/src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AtrackFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AtrackFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AtrackFrameDecoder();
+ var decoder = inject(new AtrackFrameDecoder());
verifyFrame(
binary("4052698c032a924f000147027fe5d7425f642e56060f031847bb68cb500719e26752c25bebc11c7fddce2b8ed4eff4ed863b187cc6653b5b1c1fc6803884d21aeeedae2ec6e72781d97e95b965610c1d107e5400cd5a7b7b3b592e676091c6a5893d80af9b3c63ae4de20d6e5bc60440bf2c299fbabfe268039d558e4b8589dd5173c926b7f51b916ba29f21d46ff9170793fe450072d691896e114fddce4fd29f7f2f9b74e41ca83814015e8a00ffd1f9bd475e2a44624e074a009455ab5628e39fce8036a09368cf1d2ba0d2653b979c0a00e9edc82335a56d1ee6071401d468b0f4cd761a743d011401d15b4636015721870dd0500695b2edabeabf2f4a00a514645cc83a739ad165f320c1ed401617a0a2800a2803ffd2faa68a004660aa598e00acd8f4d866d54eab3c7994284881fe11ebf5e68034e8a0086e674850927f0ae2bc4dafa5844659674451d39e49a00e1dae23d76ed67bb72211d109e4d5bd756da3b68a4b755021e30076a00cf31431a064e41e6a19a68d5396518f7a00f1ff008bfe27f31068766dbb7e1a723d3fbbf8d79aeb764748b489662be7ccbbb6820e07d4500734caa727765aa32ac0720e28026b4bb9ed7ccf2594798bb5b2a0f1f8f4a82800a2803fffd3f9b97352ae02e45004c808e4f7a997823bd005e86600618f26b7b4a9cab819fa500767a749b9403cd74162b903de803acd1e3c28aebf4d4c81401d05a4441fad682444738a00b712f2055f03e502802b14c5dffbc2ac106343ed4012a905411e94b40051401fffd4faa6992488980c793d0773400d54676df2f1e8b9e054b400564ebb77750c463b442d2119247f08f53e9401e7da85d6a12cd221d427217a856c60fe15caea9689292f2832bfac8777f3a00e67538ef150ff00665d9b4b95fba4aee46f623fa8ae26fbe24f88b49b87d3b5bd2a12e38ca3950e3d41e7228008be2ac02d423dadc09071c1047e791fcab96d77c79acdf92969279113f1c1cb7e7401876c4c939b8ba73230e5998e49ac4d66ee6bebd796462ddb9f4ed40140a12339e9dea225b1824d0025140051401fffd5f9bc676f6a7ae4af6e280255cf5c7153a7b0a0052d8715bba64bf32f39a00ed74694902bb1d306e65c500763a5afca2baed2"),
diff --git a/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java
index 4a66dbf58..be6fb5c45 100644
--- a/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AtrackProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AtrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AtrackProtocolDecoder(null);
+ var decoder = inject(new AtrackProtocolDecoder(null));
verifyNull(decoder, binary(
"4052698c032a924f000147027fe5d7425f642e56060f031847bb68cb500719e26752c25bebc11c7fddce2b8ed4eff4ed863b187cc6653b5b1c1fc6803884d21aeeedae2ec6e72781d97e95b965610c1d107e5400cd5a7b7b3b592e676091c6a5893d80af9b3c63ae4de20d6e5bc60440bf2c299fbabfe268039d558e4b8589dd5173c926b7f51b916ba29f21d46ff9170793fe450072d691896e114fddce4fd29f7f2f9b74e41ca83814015e8a00ffd1f9bd475e2a44624e074a009455ab5628e39fce8036a09368cf1d2ba0d2653b979c0a00e9edc82335a56d1ee6071401d468b0f4cd761a743d011401d15b4636015721870dd0500695b2edabeabf2f4a00a514645cc83a739ad165f320c1ed401617a0a2800a2803ffd2faa68a004660aa598e00acd8f4d866d54eab3c7994284881fe11ebf5e68034e8a0086e674850927f0ae2bc4dafa5844659674451d39e49a00e1dae23d76ed67bb72211d109e4d5bd756da3b68a4b755021e30076a00cf31431a064e41e6a19a68d5396518f7a00f1ff008bfe27f31068766dbb7e1a723d3fbbf8d79aeb764748b489662be7ccbbb6820e07d4500734caa727765aa32ac0720e28026b4bb9ed7ccf2594798bb5b2a0f1f8f4a82800a2803fffd3f9b97352ae02e45004c808e4f7a997823bd005e86600618f26b7b4a9cab819fa500767a749b9403cd74162b903de803acd1e3c28aebf4d4c81401d05a4441fad682444738a00b712f2055f03e502802b14c5dffbc2ac106343ed4012a905411e94b40051401fffd4faa6992488980c793d0773400d54676df2f1e8b9e054b400564ebb77750c463b442d2119247f08f53e9401e7da85d6a12cd221d427217a856c60fe15caea9689292f2832bfac8777f3a00e67538ef150ff00665d9b4b95fba4aee46f623fa8ae26fbe24f88b49b87d3b5bd2a12e38ca3950e3d41e7228008be2ac02d423dadc09071c1047e791fcab96d77c79acdf92969279113f1c1cb7e7401876c4c939b8ba73230e5998e49ac4d66ee6bebd796462ddb9f4ed40140a12339e9dea225b1824d0025140051401fffd5f9bc676f6a7ae4af6e280255cf5c7153a7b0a0052d8715bba64bf32f39a00ed74694902bb1d306e65c500763a5afca2baed2"));
@@ -43,6 +43,12 @@ public class AtrackProtocolDecoderTest extends ProtocolTest {
decoder.setCustom(true);
+ verifyPositions(decoder, binary(
+ "4050d78502e01d29000312fa45441d6d647d8e67647d8e67647eef190205437c021846e6001a020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010c0000000000000000000000000000000000000000000000000e647d8e85647d8e86647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010c0000000000000000000000000000000000000000000000000e647d8ea3647d8ea4647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010b0000000000000000000000000000000000000000000000000e647d8ec1647d8ec2647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010a0000000000000000000000000000000000000000000000000e647d8edf647d8ee0647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010a0000000000000000000000000000000000000000000000000e647d8efd647d8efe647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010a0000000000000000000000000000000000000000000000000e"));
+
+ verifyPositions(decoder, binary(
+ "405099280272000300014399e3f93d136438abdf644083f56440842afb2711c701b9eaee0067020003e0bb03de0000000000000007d007d00025434925454c25455425464325464c255250254d4c25534d25545225494125454f25564e254d56254256254548255a4c33255a4f3134255a4f3131255a4f3130255a4f32255a4c3400000000000000000000000000000000000000000000930025000000000000000000000000000000006438abdf644083f76440842afb2711c701b9eaee0067710003e0bb03de0100000000000007d007d00025434925454c25455425464325464c255250254d4c25534d25545225494125454f25564e254d56254256254548255a4c33255a4f3134255a4f3131255a4f3130255a4f32255a4c3400000000000000000000000000000000000000000000950025000000000000000000000000000000006438abdf644083f76440842afb2711c701b9eaee0067840003e0bb03de0100000000000007d007d00025434925454c25455425464325464c255250254d4c25534d25545225494125454f25564e254d56254256254548255a4c33255a4f3134255a4f3131255a4f3130255a4f32255a4c3400000000000000000000000000000000000000000000950025000000000000000000000000000000006438abdf644083f86440842afb2711c701b9eaee0067760003e0bb03de0100000000000007d007d00025434925454c25455425464325464c255250254d4c25534d25545225494125454f25564e254d56254256254548255a4c33255a4f3134255a4f3131255a4f3130255a4f32255a4c340000000000000000000000000000000000000000000095002500000000000000000000000000000000"));
+
verifyPositions(decoder, buffer(
"@P,7A66,153,9022,863003048505515,20210207000103,20210207000103,20210207000103,103939276,1348903,97,2,5628,8,0,0,0,0,,2000,2000,\u001a,%CI%BC,3:224:F128833445E6002C09C6\r\n"));
@@ -111,7 +117,7 @@ public class AtrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecodeCustom() throws Exception {
- var decoder = new AtrackProtocolDecoder(null);
+ var decoder = inject(new AtrackProtocolDecoder(null));
decoder.setCustom(true);
diff --git a/src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java
index fbe3ad0a3..d2ef74c02 100644
--- a/src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AuroProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AuroProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AuroProtocolDecoder(null);
+ var decoder = inject(new AuroProtocolDecoder(null));
verifyPosition(decoder, text(
"M0028T0000816398975I357325031465123E00001W*****110620150437000068DA#RD01DA240000000001+100408425+013756121100620152137231112240330004400"));
diff --git a/src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java
index 0be22b333..f46fe6a3c 100644
--- a/src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AustinNbProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AustinNbProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AustinNbProtocolDecoder(null);
+ var decoder = inject(new AustinNbProtocolDecoder(null));
verifyPosition(decoder, text(
"48666666666;2017-01-01 16:31:01;52,1133308410645;21,1000003814697;310;120;2292;1;ORANGE"));
diff --git a/src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java
index 3e64defdb..f0c9c17bd 100644
--- a/src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
@@ -9,7 +9,7 @@ public class AutoFonProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AutoFonProtocolDecoder(null);
+ var decoder = inject(new AutoFonProtocolDecoder(null));
verifyNull(decoder, binary(
"10556103592310314825728F"));
diff --git a/src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java
index 697ac8a06..be4b38a14 100644
--- a/src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AutoGradeProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AutoGradeProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AutoGradeProtocolDecoder(null);
+ var decoder = inject(new AutoGradeProtocolDecoder(null));
verifyPosition(decoder, text(
"(000000001637868324027912356171116A2250.7611N07556.9425E000.9024427197.36\u008eA0000B0000C0000D0000E0000K0000L0000M0000N0000O0000)"));
diff --git a/src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java
index 64a7459ce..3b2f2c9b7 100644
--- a/src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class AutoTrackProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class AutoTrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AutoTrackProtocolDecoder(null);
+ var decoder = inject(new AutoTrackProtocolDecoder(null));
verifyNull(decoder, binary(
"f1f1f1f1330c00201007090006de7200000000daa3"));
diff --git a/src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java
index 6138711aa..7d44e1b15 100644
--- a/src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class AvemaProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new AvemaProtocolDecoder(null);
+ var decoder = inject(new AvemaProtocolDecoder(null));
verifyAttribute(decoder, text(
"1000000000,20190527072358,121.646024,25.062135,0,0,0,0,10,0.0,1,0.02,12.32,0,0,15,2,466-5,10275,0,0.01,65EB812A000104E0,8000001234,NormanChang"),
diff --git a/src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java
index fb1984d87..ada32f8ee 100644
--- a/src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
@@ -9,7 +9,7 @@ public class Avl301ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Avl301ProtocolDecoder(null);
+ var decoder = inject(new Avl301ProtocolDecoder(null));
verifyNull(decoder, binary(
"244c0f086058500087335500010d0a"));
diff --git a/src/test/java/org/traccar/protocol/B2316ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/B2316ProtocolDecoderTest.java
index 6b9c71b0e..84b09e7b7 100644
--- a/src/test/java/org/traccar/protocol/B2316ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/B2316ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class B2316ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class B2316ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new B2316ProtocolDecoder(null);
+ var decoder = inject(new B2316ProtocolDecoder(null));
verifyPositions(decoder, false, text(
"{\"imei\":\"866349041783600\",\"data\":[{\"tm\":1631162952,\"wn\":7},{\"tm\":1631158729,\"ic\":\"89883030000059398609\",\"ve\":\"B2316.TAU.U.TH01\"},{\"tm\":1631158805,\"te\":\"312,363\",\"st\":0,\"ba\":3,\"sn\":80},{\"tm\":1631158829,\"ci\":\"505,1,8218,133179149,-108\"},{\"tm\":1631162956,\"wi\":\"101331c17f4f,-74;f46bef7953bb,-81;b09575cff1c8,-86;e2b9e5d61a7a,-88;b0ee7b4dee2f,-88;e0b9e5d61a77,-89;f66bef7953b9,-89;\",\"te\":\"335,366\",\"hr\":58,\"bp\":\"113,73\",\"st\":0,\"ba\":3,\"sn\":60},{\"tm\":1631162968,\"ci\":\"505,1,8218,133179149,-105\"}]}"));
diff --git a/src/test/java/org/traccar/protocol/BceFrameDecoderTest.java b/src/test/java/org/traccar/protocol/BceFrameDecoderTest.java
new file mode 100644
index 000000000..f25daca76
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/BceFrameDecoderTest.java
@@ -0,0 +1,26 @@
+package org.traccar.protocol;
+
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+
+public class BceFrameDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new BceFrameDecoder());
+
+ verifyNull(
+ decoder.decode(null, null, binary("23424345230d0a")));
+
+ verifyFrame(
+ binary("18ed450cf31403001501a5050a66207bde6442534451380a66207bde6440534451380a66207bde6414534451380a66207bde6416534451380a96207bde6415534451386247277bde03c0ffffc081400069f934418ce94b42001c88ee0000000000908c060103025d19ab004b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000017b5c40000000000000001010000000aa6277bde008f5344513862b7277bde03c0ffffc081400051f8344185e94b420c1c85fa0000000000d18c060103025d19ab00470000000000000000000000000000000000000000000000000000000000000000000000000000000000000017b5c40000000000000001010400000ab6277bde009153445138a0"),
+ decoder.decode(null, null, binary("18ed450cf31403001501a5050a66207bde6442534451380a66207bde6440534451380a66207bde6414534451380a66207bde6416534451380a96207bde6415534451386247277bde03c0ffffc081400069f934418ce94b42001c88ee0000000000908c060103025d19ab004b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000017b5c40000000000000001010000000aa6277bde008f5344513862b7277bde03c0ffffc081400051f8344185e94b420c1c85fa0000000000d18c060103025d19ab00470000000000000000000000000000000000000000000000000000000000000000000000000000000000000017b5c40000000000000001010400000ab6277bde009153445138a0")));
+
+ verifyFrame(
+ binary("18ed450cf31403000200a5070e"),
+ decoder.decode(null, null, binary("18ed450cf31403000200a5070e")));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/BceProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BceProtocolDecoderTest.java
index 544d49967..fdfb721c5 100644
--- a/src/test/java/org/traccar/protocol/BceProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/BceProtocolDecoderTest.java
@@ -1,15 +1,28 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
public class BceProtocolDecoderTest extends ProtocolTest {
+ @Disabled
+ @Test
+ public void testDecodeFail() throws Exception {
+
+ var decoder = inject(new BceProtocolDecoder(null));
+
+ // Needs to be fixed
+ verifyPositions(decoder, binary(
+ "18ed450cf3140300c800a53a62972f7bde03c0ffffc0814000e03e354135e34b42121c55fb0000000000d18c060103025d19ab00540000000000000000000000000000000000000000000000000000000000000000000000000000000000000017b5c400000000000000010104080162a72f7bde03c0ffffc0814000ef3e8e4431e34b42061c54fc0000000000d18c060103025d19ab00540000000000000000000000000000000000000000000000000000000000000000000000000000000000000017b5c400000000000000010100000053"));
+
+ }
+
@Test
public void testDecode() throws Exception {
- var decoder = new BceProtocolDecoder(null);
+ var decoder = inject(new BceProtocolDecoder(null));
verifyNull(decoder, binary(
"3ab90b71bc1503000300c10bff11"));
diff --git a/src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java
index c72012e5a..93c05fad6 100644
--- a/src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -9,7 +9,7 @@ public class BceProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new BceProtocolEncoder(null);
+ var encoder = inject(new BceProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java
index 3fdac8479..7ec070615 100644
--- a/src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class BlackKiteProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class BlackKiteProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new BlackKiteProtocolDecoder(null);
+ var decoder = inject(new BlackKiteProtocolDecoder(null));
verifyNull(decoder, binary(
"01150003313131313131313131313131313131209836055605BA"));
diff --git a/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java
index 4e74adf38..33496fada 100644
--- a/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class BlueProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new BlueProtocolDecoder(null);
+ var decoder = inject(new BlueProtocolDecoder(null));
verifyAttribute(decoder, binary(
"AA0056860080E3E79E0C811F80000114020207170520011F00407F8005EE1938113B270000000000000000140202071705005AC7A621121F0002000100B7000080110000000000001A3A0000000001F400000000000078"),
diff --git a/src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java
index 5b639e12b..d2af8282a 100644
--- a/src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class BoxProtocolDecoderTest extends ProtocolTest {
@@ -9,7 +9,7 @@ public class BoxProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new BoxProtocolDecoder(null);
+ var decoder = inject(new BoxProtocolDecoder(null));
verifyNull(decoder, text(
"H,BT,358281002435893,081028142432,F5813D19,6D6E6DC2"));
diff --git a/src/test/java/org/traccar/protocol/BstplProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/BstplProtocolDecoderTest.java
new file mode 100644
index 000000000..fd3561d18
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/BstplProtocolDecoderTest.java
@@ -0,0 +1,21 @@
+package org.traccar.protocol;
+
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+
+public class BstplProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new BstplProtocolDecoder(null));
+
+ verifyPosition(decoder, text(
+ "BSTPL$1,869630054439504,V,200722,045113,00.000000,0,00.00000,0,0,0,000,00,0,17,1,1,0,0,00.01,0,04.19,15B_190821,8991000907387031196F,12.27"));
+
+ verifyPosition(decoder, text(
+ "BSTPL$1,AP12AP3456,A,130720,160552,27.244183,N,83.673973,E,20,156,183,17,0,11,1,0,0,0,00.00,00,04.16,15_V1_0_0,89917380578146790443,12.16"));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java
index 6fb14b902..0dc6529e1 100644
--- a/src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class C2stekProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,10 @@ public class C2stekProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new C2stekProtocolDecoder(null);
+ var decoder = inject(new C2stekProtocolDecoder(null));
+
+ verifyPosition(decoder, text(
+ "PA$012207006145046$D#190607#123157#1#37.947087#023.768669#000.00#314.6#00000.0#4104#000#8$AP"));
verifyPosition(decoder, text(
"PA$867965024889327$D#220222#135059#0#+37.98995#+23.85141#0.00#69.2#0.0#0000#000#8#00#sz-w1001#B2600$AP"));
diff --git a/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java
index 79d27e2ab..932facaee 100644
--- a/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class CalAmpProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class CalAmpProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new CalAmpProtocolDecoder(null);
+ var decoder = inject(new CalAmpProtocolDecoder(null));
verifyPosition(decoder, binary(
"830547643586340101010400105f9c39ba5f9c302eeb36d5bddf39df700000000000000000003400040321ff9f4f0087080200001c30783330304544383946333335303139303030303030343637450d0a"));
diff --git a/src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java
index dd96c2585..e5791c706 100644
--- a/src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class CarTrackProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class CarTrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new CarTrackProtocolDecoder(null);
+ var decoder = inject(new CarTrackProtocolDecoder(null));
verifyNull(decoder, text(
"$$020040????????&A0000"));
diff --git a/src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java
index b1fe69bac..d5e60e69c 100644
--- a/src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class CarscopProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class CarscopProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new CarscopProtocolDecoder(null);
+ var decoder = inject(new CarscopProtocolDecoder(null));
verifyNull(decoder, text(
"*170821223045UB00HSO"));
diff --git a/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java
index f90fbe5ba..52c6a86a6 100644
--- a/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,15 @@ public class CastelProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new CastelProtocolDecoder(null);
+ var decoder = inject(new CastelProtocolDecoder(null));
+
+ verifyAttribute(decoder, binary(
+ "40404700043231335732303139303033353400000000000000400BBE723A5DEF723A5D000000000000000000000000000000000000030100011900030001012603030145C90D0A"),
+ Position.KEY_DTCS, "P0326");
+
+ verifyAttribute(decoder, binary(
+ "40404500033231334c323031373030303432320000000000004006e1ad205bf1ad205b48510f000000000050160000000000020400053f007c000083040001511346160d0a"),
+ Position.KEY_DTCS, "P1351");
verifyAttribute(decoder, binary(
"40403a00043231334744503230313830323133343300000000a002000001000001012011004d414c43333831434d4b4d353637313438c8fc0d0a"),
diff --git a/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java
index cdf6a7c3b..e3e59b7e7 100644
--- a/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -9,7 +9,7 @@ public class CastelProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new CastelProtocolEncoder(null);
+ var encoder = inject(new CastelProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java
index fe8586068..dd8b812fa 100644
--- a/src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class CautelaProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class CautelaProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new CautelaProtocolDecoder(null);
+ var decoder = inject(new CautelaProtocolDecoder(null));
verifyPosition(decoder, text(
"20,010907000000,14,02,18,16.816667,96.166667,1325,S,*2E"));
diff --git a/src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java b/src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java
index 04a0f74d5..aae9b434d 100644
--- a/src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class CellocatorFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class CellocatorFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new CellocatorFrameDecoder();
+ var decoder = inject(new CellocatorFrameDecoder());
verifyFrame(
binary("4D4347500BA9880B00C80A7E003800000000000806000001210A14000613000000000D4457A5F71442AC02E80300000100040707000011171408060E1C08000100000200020000FD"),
diff --git a/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java
index 3ae5350f2..01dd9f4cb 100644
--- a/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java
@@ -1,14 +1,19 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
+import org.traccar.model.Position;
public class CellocatorProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new CellocatorProtocolDecoder(null);
+ var decoder = inject(new CellocatorProtocolDecoder(null));
+
+ verifyAttribute(decoder, binary(
+ "4d4347500098ab31000856b12b2c041016002c0023b3000021f3f5ffb04c8f0100000000000078dd0004020f716445f75f3b0701126e0200b303000036002538151b0ce607ab"),
+ Position.KEY_IGNITION, true);
verifyPosition(decoder, binary(
"4D43475000856308000004B2DE1F04009E00200100000000696CF7AB002F1A00000000000000325C000402069BFDE70857E22502F41C000036000000DF0B0932100B09DC0719"));
diff --git a/src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java
index 9d42bd65d..4d5c8cfe4 100644
--- a/src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Ignore;
-import org.junit.Test;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
public class CellocatorProtocolEncoderTest extends ProtocolTest {
- @Ignore
+ @Disabled
@Test
public void testEncode() throws Exception {
- var encoder = new CellocatorProtocolEncoder(null);
+ var encoder = inject(new CellocatorProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java
index a7ed0e754..df5141e44 100644
--- a/src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class CguardProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class CguardProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new CguardProtocolDecoder(null);
+ var decoder = inject(new CguardProtocolDecoder(null));
verifyNull(decoder, text(
"IDRO:354868050655283"));
diff --git a/src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java
index 07d6368ab..1f99e02e7 100644
--- a/src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
@@ -9,7 +9,7 @@ public class CityeasyProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new CityeasyProtocolDecoder(null);
+ var decoder = inject(new CityeasyProtocolDecoder(null));
verifyNotNull(decoder, binary(
"545400853575570249020100033b3430342c34352c31303638312c31313632312c33352c31303638312c31313632322c32332c31303638312c32383938332c32332c31303638312c31313632332c32312c31303638312c32333338312c31372c31303638312c32323538332c31372c31303638312c32363434312c31330000000d352e0d0a"));
diff --git a/src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java
index 2722f6474..0b97ed9c8 100644
--- a/src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -9,7 +9,7 @@ public class CityeasyProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new CityeasyProtocolEncoder(null);
+ var encoder = inject(new CityeasyProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java
index 2924d2c4d..659c5aa9c 100644
--- a/src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class ContinentalProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class ContinentalProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new ContinentalProtocolDecoder(null);
+ var decoder = inject(new ContinentalProtocolDecoder(null));
verifyPosition(decoder, binary(
"5356003216001eb48505025b4001e90f7f18ce0f00522200400001015b4001e9000e820100000c24000100014e0400736a7a"),
diff --git a/src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java
index 1e3023b39..6e3ce2481 100644
--- a/src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class CradlepointProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class CradlepointProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new CradlepointProtocolDecoder(null);
+ var decoder = inject(new CradlepointProtocolDecoder(null));
verifyPosition(decoder, text(
"356526070063940,0,4337.19009,N,11612.34705,W,0.0,277.2,AT&T,,,-79,,-14.0,"));
diff --git a/src/test/java/org/traccar/protocol/DingtekFrameDecoderTest.java b/src/test/java/org/traccar/protocol/DingtekFrameDecoderTest.java
index 6236410b3..6219b3da4 100644
--- a/src/test/java/org/traccar/protocol/DingtekFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DingtekFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class DingtekFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class DingtekFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new DingtekFrameDecoder();
+ var decoder = inject(new DingtekFrameDecoder());
verifyFrame(
binary("383030303031303131453032383830303138303030303030303030313545303038303545433430303031313836383832323034303130343433303831"),
diff --git a/src/test/java/org/traccar/protocol/DingtekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DingtekProtocolDecoderTest.java
index 8b3d07c22..3131ee1df 100644
--- a/src/test/java/org/traccar/protocol/DingtekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DingtekProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class DingtekProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class DingtekProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new DingtekProtocolDecoder(null);
+ var decoder = inject(new DingtekProtocolDecoder(null));
verifyPosition(decoder, text(
"800001011e0692001a00000000016e008027c40000186962703655111781"));
diff --git a/src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java
index 4492b3ed0..a9b80664c 100644
--- a/src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class DishaProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class DishaProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new DishaProtocolDecoder(null);
+ var decoder = inject(new DishaProtocolDecoder(null));
verifyPosition(decoder, text(
"$A#A#864161028848856#A#053523#010216#2232.7733#N#08821.1940#E#002.75#038.1#09#00.8#1800#0#000#0000#9999#11.7#285.7#0001*"));
diff --git a/src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java
index 31d0efa12..c2449ea91 100644
--- a/src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
import io.netty.handler.codec.http.HttpMethod;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class DmtHttpProtocolDecoderTest extends ProtocolTest {
@@ -9,7 +9,7 @@ public class DmtHttpProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new DmtHttpProtocolDecoder(null);
+ var decoder = inject(new DmtHttpProtocolDecoder(null));
verifyAttributes(decoder, request(HttpMethod.POST, "/",
buffer("{\"date\":\"2021-12-12T16:04:52Z\",\"device\":{\"sn\":\"416581\",\"prod\":85,\"rev\":1,\"fw\":\"1.12\",\"iccid\":\"89011702278612797427\",\"imei\":\"351358810439486\"},\"sqn\":1549,\"reason\":42,\"counters\":[{\"id\":0,\"val\":5304},{\"id\":3,\"val\":3200},{\"id\":4,\"val\":5066},{\"id\":128,\"val\":1},{\"id\":129,\"val\":8},{\"id\":130,\"val\":0},{\"id\":131,\"val\":0},{\"id\":132,\"val\":0},{\"id\":134,\"val\":1},{\"id\":138,\"val\":0},{\"id\":139,\"val\":36},{\"id\":142,\"val\":1629023},{\"id\":145,\"val\":0},{\"id\":146,\"val\":1}]}")));
diff --git a/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java
index 82a4cd5ff..6919f8ed8 100644
--- a/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class DmtProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class DmtProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new DmtProtocolDecoder(null);
+ var decoder = inject(new DmtProtocolDecoder(null));
verifyNull(decoder, binary(
"0255003300001b00003335333232393032373533393235310038393931353030303030303030313330343539340000000403041910780603"));
diff --git a/src/test/java/org/traccar/protocol/DolphinProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DolphinProtocolDecoderTest.java
index 0215973e8..b24f30965 100644
--- a/src/test/java/org/traccar/protocol/DolphinProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DolphinProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class DolphinProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class DolphinProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new DolphinProtocolDecoder(null);
+ var decoder = inject(new DolphinProtocolDecoder(null));
verifyPositions(decoder, binary(
"ababff8f0300000100000100e03c0b86c70e03005c0f0000ab4cd12d0aa9010d0d7f0e4215f6fe6c421d00b0ce4420122daa9a9042359a99f9413806455e53fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa0662404801010ce41bb8f4cc2ad801fe98f3030893dd9a010001019299f303155400000007b401000000000072ac01b99401f8de8a0adc03900e0049000003004bfa010aa7010d4f7f0e421505ff6c421dcd1cce4420112d3ef984423552b89e413806456053fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06623e4201010ce41bd8f4cc2a20ff98f3030193dd9a010001019399f30315420000000000000000000072ad018f950181df8a0aee03cd0d004b000003004bfa010aa7010da67f0e42154fff6c421d3393cd4420112d073c9942358fc2df413806456253fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06623e4c010111f51d88f5cc2a308199f3030293dd9a010001019599f303154c0000000000000000000072ad01ef95018bdf8a0aee03d30d004a000003004bfa010aa9010dfd800e421525006d421d3373d04420102da5b7aa4235ec51c4413806456853fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa0662405501010ef01db0f6cc2aa8018899f3030793dd9a010001019c99f3031555000000068a010000000000739d01df9501acdf8a0ac0028a150031000003004bfa010aa8010d3b830e421561016d421dcddcd04420102d8edda94235cdccbe413806457353fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06623f5401010ef01db8f8cc2a88029499f3030c93dd9a01000101a899f303155500000004480000000000728a018f9501e5df8a0aa9018d280015000003004bfa010aa8010ddd850e4215b3026d421dcd3cd04420112d2e9ba942359a99af413806458053fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06623f5401010df01df0facc2ab802a199f3030d93dd9a01000101b599f303155500000005760000000000728b01f59401a2e08a0a9b01c12b0018000003004bfa010aa9010d4a870e421554036d421d66d6cf4420112d5f29a842355c8faa413806458753fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa0662405401010dea1d98fccc2aa801a899f3030793dd9a01000101bc99f303155400000007a4010000000000719701b29401bae08a0a9202be180026000003004bfa010aa7010da7870e421591036d421d33d3cf4420112d6329a942353333a7413806458953fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06623e5401010df51dc8fccc2a30aa99f3030293dd9a01000101be99f3031554000000022c0000000000719901db9401c3e08a0aae02a016002b000003004bfa010aa7010d1a880e4215b6036d421d33e3cf4420112ddc45aa423514aea3413806458b53fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06623e5501010df51df8fccc2a30ac99f3030293dd9a01000101c099f303155500000002320000000000719e01f69401d1e08a0a9f02b3170031000003004bfa010aa8010d50890e42154d046d421d3363d04420102da0b7a94235d7a3a2413806459253fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06623f5401010edf1d88fecc2a9001b399f3030793dd9a01000101c799f303155400000000000000000000729a01e69501f7e08a0ab0028e16002d000003004bfa010aa9010d188c0e421573056d421d00c0ce4420102d300c84423514ae7741380645a053fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06624042010110da1dd080cd2ac802c199f3030e93dd9a01000101d599f303155500000009e2010000000000729801b19501afe18a0a97029018002a000003004bfa010aa7010d528c0e42159d056d421d3313cf4420102dfec98c423552b8c241380645a053fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06623e46010110da1df080cd2a20c299f3030193dd9a01000101d699f303154600000000000000000000729701df9501b8e18a0aa002b9170029000003004bfa010aa9010d198f0e42159e066d421d9a49d04420112dfae6a642359a999941380645ad53fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06624053010111e51da883cd2ab802cf99f3030d93dd9a01000101e399f30315540000000ca4020000000000729601c49501f1e18a0a9102dc180028000003004bfa010aa7010da68f0e4215e9066d421d9a19d044200f2d83dda74235ec519441380645b153fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06623e53010111e51df083cd2a48d299f3030393dd9a01000101e699f303155300000003400000000000729701de950183e28a0a8e02ff180028000003004bfa010aa7010d40900e42151a076d421d33c3cf4420102d717e9b423548e15e41380645b453fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06623e4d010110e51db884cd2a48d599f3030393dd9a01000101e999f303154d00000003420000000000729801bf950191e28a0a9a02f117002a000003004bfa010aa7010d5f900e42153c076d421d66c6cf44200f2de3028d4235713daa41380645b553fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06623e46010110da1dc884cd2a10d699f3030193dd9a01000101ea99f303154600000001120000000000729901bf950191e28a0a98029318002b000003004bfa010aa7010dae900e42153d076d421d9ad9cf44200f2d324fa342357b144241380645b653fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06623e51010110da1de884cd2a20d799f3030193dd9a01000101eb99f303155100000000000000000000729b01a5950196e28a0aa2029b17002c000003004bfa010aa7010d08910e42157e076d421d33b3cf4420102d51b79a42357b14b241380645b853fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06623e4d010110da1d9885cd2a30d999f3030293dd9a01000101ed99f3031552000000022c0000000000729b01ca95019be28a0ab602e815002f000003004bfa010aa9010d3b930e42153f086d421d9a99d044200f2d5a3ca9423552b88441380645c153fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06624054010110f51d9087cd2af801e499f3030b93dd9a01000101f899f30315540000000bfa010000000000729901cf9501cee28a0ac502f814002e000003004bfa010aa9010df1950e421558096d421d6646d24420102da3a4a842357b149441380645cf53fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa0662405401010eea1dc889cd2ab802f199f3030d93dd9a01000101859af303155500000008be010000000000729901c7950190e38a0a9c02da17002c000003004bfa010aa9010dcf970e4215260a6d421d6676d34420112d653cab423552b89e41380645d853fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa0662405501010efa1ba08bcd2ad801fa99f3030993dd9a010001018e9af303155600000007a8010000000000729e01bb9501bae38a0ac00284150031000003004bfa010aa8010de89a0e4215510b6d421d00a0d44420112d1aaea74235cdcc6841380645e653fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06623f53010110f51d808ecd2ae002899af3030f93dd9a010001019d9af30315550000000460000000000073a401e59501fce38a0a9003e510003e000003004bfa010aa9010d6b9c0e4215b00b6d421d00b0d44420112dd46bac423585eb0541380645ed53fc5f48015a41050a0b1e29323334353637464850649601a401a601aa01ab01ad01b401b501b601b701b801c905ca05cb05cd05d105d205e605e705ef059c069e06a206a906aa06624056010110ea1da88fcd2aa801919af3030893dd9a01000101a59af303155600000008a801000000000073a201a19501a1e48a0a8103ce110038000003004bfa01"));
diff --git a/src/test/java/org/traccar/protocol/Dsf22FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Dsf22FrameDecoderTest.java
index fc18b0560..b0c90ef7c 100644
--- a/src/test/java/org/traccar/protocol/Dsf22FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Dsf22FrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Dsf22FrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Dsf22FrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Dsf22FrameDecoder();
+ var decoder = inject(new Dsf22FrameDecoder());
verifyFrame(
binary("4642000101A8EE5F0ECA5FF421B33F524E32610401"),
diff --git a/src/test/java/org/traccar/protocol/Dsf22ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Dsf22ProtocolDecoderTest.java
index 4089c208c..dbf6f782c 100644
--- a/src/test/java/org/traccar/protocol/Dsf22ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Dsf22ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Dsf22ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Dsf22ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Dsf22ProtocolDecoder(null);
+ var decoder = inject(new Dsf22ProtocolDecoder(null));
verifyPositions(decoder, binary(
"4642a82d01c8f6aa1af1792c0c1411eb61001e0000"));
diff --git a/src/test/java/org/traccar/protocol/DualcamFrameDecoderTest.java b/src/test/java/org/traccar/protocol/DualcamFrameDecoderTest.java
index 46f32a8ae..495e20e8e 100644
--- a/src/test/java/org/traccar/protocol/DualcamFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DualcamFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class DualcamFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class DualcamFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new DualcamFrameDecoder();
+ var decoder = inject(new DualcamFrameDecoder());
verifyFrame(
binary("000000050001403a4abaa31444000400"),
diff --git a/src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java
index 3dd11bdf7..de70e2b63 100644
--- a/src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class DualcamProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class DualcamProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new DualcamProtocolDecoder(null);
+ var decoder = inject(new DualcamProtocolDecoder(null));
verifyNull(decoder, binary(
"000000050001403a4abaa31444000400"));
diff --git a/src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java
index 368f8b4ac..05b2757ad 100644
--- a/src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class DwayProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class DwayProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new DwayProtocolDecoder(null);
+ var decoder = inject(new DwayProtocolDecoder(null));
verifyPosition(decoder, text(
"AA55,36,10024,1,171025,161055,36.0294,-79.7881,201, 2.5,111,1000,0000,00000,3578,0,0,0,D"));
diff --git a/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java
index 5fda7fb28..bcd9aea45 100644
--- a/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class EasyTrackProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class EasyTrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new EasyTrackProtocolDecoder(null);
+ var decoder = inject(new EasyTrackProtocolDecoder(null));
verifyNotNull(decoder, text(
"*ET,354522180593498,JZ,0,20222,262,724,4#"));
diff --git a/src/test/java/org/traccar/protocol/EasyTrackProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/EasyTrackProtocolEncoderTest.java
index 79b4e66e3..a2a720263 100644
--- a/src/test/java/org/traccar/protocol/EasyTrackProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/EasyTrackProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class EasyTrackProtocolEncoderTest extends ProtocolTest {
@Test
- public void testEncodeEngineStop() {
+ public void testEncodeEngineStop() throws Exception {
- var encoder = new EasyTrackProtocolEncoder(null);
+ var encoder = inject(new EasyTrackProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java
index c1cc3c39a..6e2c41a7f 100644
--- a/src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class EelinkProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new EelinkProtocolDecoder(null);
+ var decoder = inject(new EelinkProtocolDecoder(null));
verifyPositions(decoder, binary(
"454c029249a50354679090044671676712004321315f3cf43503fc94d3760c79328a0129000000000a01f9000190330905580d2e046f118a04ec00000000ccc7086c02fe000000000000000000000000000000000000676712004321325f3cf43e03fc94d3760c79328a0129000000000901f9000190330905580d2e046f117b04ec00000000ccc7086d02ff000000000000000000000000000000000000676712004321335f3cf44703fc94d3760c79328a0129000000000901f9000190330905580d2e046f117f04ec00000000ccc7086d02ff000000000000000000000000000000000000676712004321345f3cf45303fc94d3760c79328a0129000000000901f9000190330905580d2e046f119d04ec00000000ccc7086d02ff000000000000000000000000000000000000676712004321355f3cf45c03fc94d3760c79328a0129000000000801f9000190330905580d2e046f11a304ec00000000ccc7086d02ff000000000000000000000000000000000000676712004321365f3cf46603fc94d3760c79328a0129000000000801f9000190330905580d2e046f118804df00000000ccc7086d02ff000000000000000000000000000000000000676712004321375f3cf47103fc94d3760c79328a0129000000000901f9000190330905580d2e046f119704ec00000000ccc7086d02ff000000000000000000000000000000000000676712004321385f3cf47a03fc94d3760c79328a0129000000000901f9000190330905580d2e046f118204ec00000000ccc7086e0300000000000000000000000000000000000000676712004321395f3cf48303fc94d3760c79328a0129000000000901f9000190330905580d2e046f117604df00000000ccc7086e0300000000000000000000000000000000000000"));
diff --git a/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java
index 616ca0b52..300a1c5b6 100644
--- a/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java
@@ -1,21 +1,34 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
public class EelinkProtocolEncoderTest extends ProtocolTest {
@Test
- public void testEncode() throws Exception {
+ public void testEncodeTcp() throws Exception {
+
+ var encoder = inject(new EelinkProtocolEncoder(null, false));
Command command = new Command();
command.setDeviceId(1);
command.setType(Command.TYPE_ENGINE_STOP);
- verifyCommand(new EelinkProtocolEncoder(null, false), command, binary("676780000f0000010000000052454c41592c3123"));
+ verifyCommand(encoder, command, binary("676780000f0000010000000052454c41592c3123"));
+
+ }
+
+ @Test
+ public void testEncodeUdp() throws Exception {
+
+ var encoder = inject(new EelinkProtocolEncoder(null, true));
+
+ Command command = new Command();
+ command.setDeviceId(1);
+ command.setType(Command.TYPE_ENGINE_STOP);
- verifyCommand(new EelinkProtocolEncoder(null, true), command, binary("454c001eb41a0123456789012345676780000f0000010000000052454c41592c3123"));
+ verifyCommand(encoder, command, binary("454c001eb41a0123456789012345676780000f0000010000000052454c41592c3123"));
}
diff --git a/src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java b/src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java
index a1acb1e9d..af5e77116 100644
--- a/src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class EgtsFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class EgtsFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new EgtsFrameDecoder();
+ var decoder = inject(new EgtsFrameDecoder());
verifyFrame(
binary("0100020B0025003A5701C91A003A5701CD6E68490202101700CBB4740F7617FD924364104F116A0000000000010300001EC2"),
diff --git a/src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java
index dcf70bcae..aa0d666b1 100644
--- a/src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class EgtsProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class EgtsProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecodeWithObjectId() throws Exception {
- var decoder = new EgtsProtocolDecoder(null);
+ var decoder = inject(new EgtsProtocolDecoder(null));
verifyNull(decoder, binary(
"0100020b002300020001871c00020000010105190000ab0800006247396e615734366347467a63336476636d513daadf"));
@@ -31,7 +31,7 @@ public class EgtsProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecodeWithAuth() throws Exception {
- var decoder = new EgtsProtocolDecoder(null);
+ var decoder = inject(new EgtsProtocolDecoder(null));
verifyNull(decoder, binary(
"0100010b002200c06401f21700c1640171360d00010101140071360d000238363539303500000000000000000047fc"));
diff --git a/src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java
index 14e982e39..c53d65ceb 100644
--- a/src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class EnforaProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class EnforaProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new EnforaProtocolDecoder(null);
+ var decoder = inject(new EnforaProtocolDecoder(null));
verifyNull(decoder, binary(
"000A08002020202020303131303730303030353730323637"));
diff --git a/src/test/java/org/traccar/protocol/EnnfuProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EnnfuProtocolDecoderTest.java
index 4afa5921f..5f1d152f6 100644
--- a/src/test/java/org/traccar/protocol/EnnfuProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EnnfuProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class EnnfuProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class EnnfuProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new EnnfuProtocolDecoder(null);
+ var decoder = inject(new EnnfuProtocolDecoder(null));
verifyPosition(decoder, text(
"Ennfu:354679095321652,041504.00,A,3154.86654,N,11849.08737,E,0.053,,080121,20,3.72,21.4,V0.01"));
diff --git a/src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java
index 6a455975d..68a3ee9e3 100644
--- a/src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class EnvotechProtocolDecoderTest extends ProtocolTest {
@@ -8,10 +8,17 @@ public class EnvotechProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new EnvotechProtocolDecoder(null);
+ var decoder = inject(new EnvotechProtocolDecoder(null));
verifyPosition(decoder, text(
- "$80SLM,02,F,AB0010,130410155921,431750216,000040,0000,,00000000,'13041015592110476673N10111459E001281*2A"));
+ "$80IVM,03,E002215,E002215,110422061936,672763902,126423,0180,000000,00018600,0.0000'11042206193710406325S03966094E000118*42D6#"));
+
+ verifyPosition(decoder, text(
+ "$80SLM,62,000F,F015727,020522053200,611000000,000391,C080,000,80028900,85010000'02052205320110399426S03970217E000145*E0C2#"));
+
+ verifyPosition(decoder, text(
+ "$80SLM,02,F,AB0010,130410155921,431750216,000040,0000,,00000000,'13041015592110476673N10111459E001281*2A"),
+ position("2010-04-13 15:59:21.000", true, 4.76673, 101.11459));
verifyPosition(decoder, text(
"$80SLM,82,F,AB0010,130410155921,431750216,000040,0000,,00000000,'13041015592110476673N10111459E001281@B0,F,C456,038,00,M234567,,,1A2A3A4A5A6A*4E"));
diff --git a/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java
index d0d9e3c41..4cccff878 100644
--- a/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class EsealProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class EsealProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new EsealProtocolDecoder(null);
+ var decoder = inject(new EsealProtocolDecoder(null));
verifyPosition(decoder, text(
"##S,eSeal,1000821,256,3.0.6,Normal,34,2017-08-31,08:14:40,15,A,25.708828N 100.372870W,10,0,Close,0.71,0:0:3:0,3.8,-73,E##"));
diff --git a/src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java
index 88be3ebc9..e87a56b67 100644
--- a/src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class EsealProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new EsealProtocolEncoder(null);
+ var encoder = inject(new EsealProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java b/src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java
index c3926c8d7..830ee4df0 100644
--- a/src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class EskyFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class EskyFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new EskyFrameDecoder();
+ var decoder = inject(new EskyFrameDecoder());
verifyNull(
decoder.decode(null, null, binary("00")));
diff --git a/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java
index ace55f934..feec3ebfb 100644
--- a/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class EskyProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new EskyProtocolDecoder(null);
+ var decoder = inject(new EskyProtocolDecoder(null));
verifyAttribute(decoder, text(
"ET;0;860337031066546;R;9+200717114059+41.32053+19.80761+0.30+0+0x2+8+40381744+0+1409+11"),
diff --git a/src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java
index 29d11e02f..ccd7d4d20 100644
--- a/src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class ExtremTracProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class ExtremTracProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new ExtremTracProtocolDecoder(null);
+ var decoder = inject(new ExtremTracProtocolDecoder(null));
verifyPosition(decoder, text(
"$GPRMC,862106020628733,050859.000,A,1404.8573,N,08710.9967,W,0.00,0,080117,0,,00C8,00218,99,,,,,,0.00"));
diff --git a/src/test/java/org/traccar/protocol/FifotrackFrameDecoderTest.java b/src/test/java/org/traccar/protocol/FifotrackFrameDecoderTest.java
index 32657b277..de320778a 100644
--- a/src/test/java/org/traccar/protocol/FifotrackFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FifotrackFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class FifotrackFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class FifotrackFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new FifotrackFrameDecoder();
+ var decoder = inject(new FifotrackFrameDecoder());
verifyFrame(
binary("24243132362c3836393436373034393239303738372c324138432c4130312c2c3139303431333135333235342c412c2d31352e3132373836382c33392e3236323530362c302c3136322c3431352c38303937323234332c302c303030302c30302c302c3634337c337c353141467c424632462c3141337c3446367c3833327c302c312c2a3534"),
diff --git a/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java
index 6480d1dc4..77778d885 100644
--- a/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,14 @@ public class FifotrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new FifotrackProtocolDecoder(null);
+ var decoder = inject(new FifotrackProtocolDecoder(null));
+
+ verifyAttributes(decoder, buffer(
+ "$$159,866344056951341,399D,A03,,230716222659,240|8|2724|20EEF33,4.20,100,003E,1,AE233FC0D2E0:-65|3E286D5FB6E8:-65|28BD890A4A0E:-67|8ED81B5DFC3A:-70|8AD81B5DFC3A:-70*5F"));
+
+ verifyAttribute(decoder, buffer(
+ "$$99,865413050150407,7F,A03,,230626072722,460|0|25FC|AC2AB0B,3.74,52,0019,0,A,0,13,22.643466,114.018211*74"),
+ Position.KEY_SATELLITES, 13);
verifyPosition(decoder, buffer(
"$$95,866104023192332,1,A03,,210414055249,460|0|25FC|104C,4.18,100,000F,0,A,2,9,22.643175,114.018150*75"));
diff --git a/src/test/java/org/traccar/protocol/FifotrackProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/FifotrackProtocolEncoderTest.java
index 2da7f0842..643c9202d 100644
--- a/src/test/java/org/traccar/protocol/FifotrackProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/FifotrackProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class FifotrackProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new FifotrackProtocolEncoder(null);
+ var encoder = inject(new FifotrackProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java
index 88fdb0959..47a6eab87 100644
--- a/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
import io.netty.handler.codec.http.HttpMethod;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class FlespiProtocolDecoderTest extends ProtocolTest {
@@ -9,7 +9,7 @@ public class FlespiProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new FlespiProtocolDecoder(null);
+ var decoder = inject(new FlespiProtocolDecoder(null));
verifyPositions(decoder, request(HttpMethod.POST, "/",
buffer("[{\"position.speed\":0,\"position.latitude\":53.90573,\"time.valid.status\":true,\"timestamp\":1506956075,\"position.satellites\":10,\"message.buffered.status\":false,\"business.mode.status\":true,\"gps.status\":true,\"position.longitude\":27.455848,\"position.direction\":0,\"ident\":\"605630\"},{\"siren.status\":false,\"business.mode.status\":true,\"position.satellites\":8,\"timestamp\":1506695785,\"led.status\":false,\"position.latitude\":53.905569,\"position.longitude\":27.455986,\"position.speed\":0,\"gradual.stop.status\":false,\"position.direction\":262.643854,\"hardware.version.enum\":223,\"vehicle.mileage\":160,\"message.buffered.status\":false,\"blinkers.status\":false,\"ident\":\"605630\",\"position.altitude\":233.48,\"immobilizer.status\":false}]")));
diff --git a/src/test/java/org/traccar/protocol/FlexApiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlexApiProtocolDecoderTest.java
index c819cd8bf..bd54b4be0 100644
--- a/src/test/java/org/traccar/protocol/FlexApiProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FlexApiProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class FlexApiProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class FlexApiProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new FlexApiProtocolDecoder(null);
+ var decoder = inject(new FlexApiProtocolDecoder(null));
verifyAttributes(decoder, text(
"${\"topic\":\"v1/VF3102021113001/motion/info\",\"payload\":{\"motion.ts\":1641885877,\"motion.ax\":0.006344,\"motion.ay\":0.289384,\"motion.az\":-0.939156,\"motion.gx\":0.420000,\"motion.gy\":0.420000,\"motion.gz\":-0.280000}}xx"));
diff --git a/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java
index 3e988ba4f..b0b0910c6 100644
--- a/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class FlexCommProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class FlexCommProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new FlexCommProtocolDecoder(null);
+ var decoder = inject(new FlexCommProtocolDecoder(null));
verifyPosition(decoder, text(
"7E00865067022408382201705302358271024932258006712785200700022601010224100040002C5002A2210001000000010012342107"));
diff --git a/src/test/java/org/traccar/protocol/FlexibleReportProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlexibleReportProtocolDecoderTest.java
index 8763887a5..3bff46df0 100644
--- a/src/test/java/org/traccar/protocol/FlexibleReportProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FlexibleReportProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class FlexibleReportProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class FlexibleReportProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new FlexibleReportProtocolDecoder(null);
+ var decoder = inject(new FlexibleReportProtocolDecoder(null));
verifyPosition(decoder, binary(
"7d010015875000013001001028fd98991830002e7fffffff0c28fd989903f6540a07f250ed00000f02f2140f5ea20000000000000202d4000a1f8b0100000708ffff"));
diff --git a/src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java
index 0c1c18a0c..2e0274d11 100644
--- a/src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
@@ -9,7 +9,7 @@ public class FlextrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new FlextrackProtocolDecoder(null);
+ var decoder = inject(new FlextrackProtocolDecoder(null));
verifyNull(decoder, text(
"-1,LOGON,7000000123,8945000000"));
diff --git a/src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java
index 439a5553a..7918243e6 100644
--- a/src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class FoxProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class FoxProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new FoxProtocolDecoder(null);
+ var decoder = inject(new FoxProtocolDecoder(null));
verifyPosition(decoder, text(
"<fox><gps id=\"10\" data=\"51,A,010416,085317,4444.4158,N,02025.4466,E,1,182,,1110111111110111 141 0 0 0 0 0 10010000 10142,018C81851800009B\"/></fox>"));
diff --git a/src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java
index c8f7a444b..f8cdb8934 100644
--- a/src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class FreedomProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class FreedomProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new FreedomProtocolDecoder(null);
+ var decoder = inject(new FreedomProtocolDecoder(null));
verifyPosition(decoder, text(
"IMEI,353358011714362,2014/05/22, 20:49:32, N, Lat:4725.9624, E, Lon:01912.5483, Spd:5.05"),
diff --git a/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java
index 6a7a15397..53ed07da7 100644
--- a/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class FreematicsProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,10 @@ public class FreematicsProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new FreematicsProtocolDecoder(null);
+ var decoder = inject(new FreematicsProtocolDecoder(null));
+
+ verifyPositions(decoder, text(
+ "UCFLFAYM#0:33770,24:300,82:53.000000,*F9"));
verifyPositions(decoder, text(
"M0ZR4X0#0:204391,11:140221,10:8445000,A:49.215920,B:18.737755,C:410,D:0,E:208,24:1252,20:0;0;0,82:47*B5"));
diff --git a/src/test/java/org/traccar/protocol/FutureWayFrameDecoderTest.java b/src/test/java/org/traccar/protocol/FutureWayFrameDecoderTest.java
index b8eb3908e..40d8e619e 100644
--- a/src/test/java/org/traccar/protocol/FutureWayFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FutureWayFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class FutureWayFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class FutureWayFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new FutureWayFrameDecoder();
+ var decoder = inject(new FutureWayFrameDecoder());
verifyFrame(
binary("343130303030303039424130303030344750533a562c3230303930323039333333332c302e3030303030304e2c302e303030303030452c302e3030302c302e3030300d0a574946493a332c317c39302d36372d31432d46372d32312d36437c353226327c38302d38392d31372d43362d37392d41307c353426337c34302d46342d32302d45462d44442d32417c35380d0a4c42533a3436302c302c34363437353036362c36390d0a36413432"),
diff --git a/src/test/java/org/traccar/protocol/FutureWayProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FutureWayProtocolDecoderTest.java
index fbb0a2aba..e8af86d66 100644
--- a/src/test/java/org/traccar/protocol/FutureWayProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FutureWayProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class FutureWayProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class FutureWayProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new FutureWayProtocolDecoder(null);
+ var decoder = inject(new FutureWayProtocolDecoder(null));
verifyNull(decoder, text(
"410000003F2000020,IMEI:354828100126461,battery level:6,network type:7,CSQ:236F42"));
diff --git a/src/test/java/org/traccar/protocol/G1rusProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/G1rusProtocolDecoderTest.java
new file mode 100644
index 000000000..059fc21df
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/G1rusProtocolDecoderTest.java
@@ -0,0 +1,18 @@
+package org.traccar.protocol;
+
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+
+public class G1rusProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new G1rusProtocolDecoder(null));
+
+ verifyPositions(decoder, binary(
+ "f84604000d85f5e55298004b012ad7d524003d1d0f50726f6d61205361742031303030201556312e31302656312e312e340a03120fa0142b8475a157050401846dfc060175120a29a10d02440111002100310041005107d10ef8"));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java
index 0d3199eab..530f0930e 100644
--- a/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java
@@ -1,16 +1,20 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class GalileoFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GalileoFrameDecoder();
+ var decoder = inject(new GalileoFrameDecoder());
+
+ assertEquals(
+ binary("01003f01001c475b166133303035333430363431383437393000001d000064897bb003000b0221c20512a60a0000000802000f209d7b8964300f2536fbfd103c1d01"),
+ decoder.decode(null, null, binary("01003f01001c475b166133303035333430363431383437393000001d000064897bb003000b0221c20512a60a0000000802000f209d7b8964300f2536fbfd103c1d01")));
assertEquals(
binary("011780011102e603383633353931303238393630323437043200801c"),
diff --git a/src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java
index 66b375b8a..2611832ff 100644
--- a/src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class GalileoProtocolDecoderTest extends ProtocolTest {
@@ -8,12 +8,15 @@ public class GalileoProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GalileoProtocolDecoder(null);
+ var decoder = inject(new GalileoProtocolDecoder(null));
verifyPositions(decoder, binary(
"011801018202130338363833343530333230343234323604640010a406207caa9f5b300c830a7901ca0ec802330000000034b802350540003e41703f422b1043234504004600e09000000000a000a100a200a300a400a500a600a700a800a900aa00ab00ac00ad00ae00af00b00000b10000b20000b30000b40000b50000b60000b70000b80000b90000c000000000c100000000c200000000c300000000c400c500c600c700c800c900ca00cb00cc00cd00ce00cf00d000d100d200d4d3140000d60000d70000d80000d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f300000000f400000000f500000000f600000000f700000000f800000000f9000000008960"));
verifyPositions(decoder, binary(
+ "01bf83043200101ee4209832bc62300549589302511aaa013300002e00342e02350440003b41b15d42d50e4326450e0046040050000051000052fc5c5300006100008b009000000000d400000000e201000000e376000000e4efce0100e53b590200e600000000e773000000e800000000e9a002d007ea140000d6021b00f8430220ac760000000000000000043200101de4201232bc62300549589302511aaa013300002e00342e02350440012b41b55d42d40e4326450e0046040050000051000052145d5300006100008b009000000000d400000000e201000000e376000000e4efce0100e53b590200e600000000e773000000e800000000e9a002d007ea140000d6021b00f8430220ac760000000000000000043200101ce4208e2ebc62300549589302511aaa013300002e00342e02350440013b41a95d42cd0e4325450f0046040050000051000052235d5300006100008b009000000000d400000000e201000000e376000000e4efce0100e53b590200e600000000e773000000e802000000e9a002d007ea140000d6021b00f8430220ac760000000000000000043200101be4208b2ebc62300549589302511aaa013300002e00342e02350440013b41a45d42cd0e432545090046040050000051000052115d5300006100008b009000000000d400000000e201000000e375000000e48ac90100e53a590200e673000000e773000000e806000000e9a002d007ea140000d6021b00f8430220ac760000000000000000043200101ae420642ebc62300549589302511aaa013300002e00342e02350440013b419f5d42cd0e4324450b00460600500000519313521c5d5300006100008b009000000000d400000000e201000000e300000000e406000000e5c5580200e673000000e700000000e801000000e9a002d007ea140000d6021b00f8430220ac7600000000000000000432001019e420632ebc62300549589302511aaa013300002e00342e02350440013b41725d42cd0e4324450b0046060050000051ab1352035d5300006100008b009000000000d400000000e201000000e300000000e406000000e5c5580200e673000000e700000000e8d6021b00e9a002d007ea140000d6021b00f8430220ac7600000000000000000432001018e4205c2ebc62300549589302511aaa013300002e00342e02350440013b41955d42cd0e4324450a00460400500000510000520b5d5300006100008b009000000000d400000000e201000000e30d000000e4a4350000e5c5580200e600000000e700000000e8d6021b00e9a002d007ea140000d6021b00f8430220ac76000000000000000099f3"));
+
+ verifyPositions(decoder, binary(
"017583018202120338363833343530333230363635373304520010384520c850975b300cc03a910107cbf9023365000607341300350640012a41236a4215104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d4993b0500d64100d70000d8be02d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f300000000018202120338363833343530333230363635373304520010394520c950975b300cab3a91010ecbf902336000be06341300350640012a41266a4216104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d49b3b0500d64100d70000d8bc02d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f3000000000182021203383638333435303332303636353733045200103a4520ca50975b300c953a910113cbf9023358008f06341300350640012a41206a4215104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d49e3b0500d64100d70000d8ba02d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f3000000000182021203383638333435303332303636353733045200103b45204251975b300c6d3a91011dcbf9023300008a06341300350640013a41726a4216104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d4a33b0500d64800d70000d80003d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f3000000000182021203383638333435303332303636353733045200103c4520bb51975b300c6d3a91011dcbf9023300008a06341300350640013a41816a4216104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d4a33b0500d64800d70000d80003d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f300000000e007"));
verifyNull(decoder, binary(
@@ -42,4 +45,21 @@ public class GalileoProtocolDecoderTest extends ProtocolTest {
}
+ @Test
+ public void testDecodeIridium() throws Exception {
+
+ var decoder = inject(new GalileoProtocolDecoder(null));
+
+ decoder.setCompressed(false);
+
+ verifyPosition(decoder, binary(
+ "01004e01001c0747ea59333030323334303639363034353930000012000063c85e6903000b0321a8f846aba50000000202001e205f5ec863300c4643fdfdbbe6c8fb330000000034e7013505d400000000"));
+
+ /*decoder.setCompressed(true);
+
+ verifyPosition(decoder, binary(
+ "01003a01001c07553e40333030323334303639363034353930020021000063d1921c03000b0321ac2c4545b20000009f02000ac200000000db00000000"));*/
+
+ }
+
}
diff --git a/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java
index b25100c48..af640f3d4 100644
--- a/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -9,7 +9,7 @@ public class GalileoProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new GalileoProtocolEncoder(null);
+ var encoder = inject(new GalileoProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java
index 24686e220..6f1bd88db 100644
--- a/src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java
@@ -1,9 +1,9 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class GatorProtocolDecoderTest extends ProtocolTest {
@@ -17,7 +17,7 @@ public class GatorProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GatorProtocolDecoder(null);
+ var decoder = inject(new GatorProtocolDecoder(null));
verifyAttributes(decoder, binary(
"242480002600341cad190917022021812497260280594200000000c047010000135400009bb600ff00b90d"));
diff --git a/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java
new file mode 100644
index 000000000..af6c71e37
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/GatorProtocolEncoderTest.java
@@ -0,0 +1,23 @@
+package org.traccar.protocol;
+
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+import org.traccar.model.Command;
+import org.traccar.model.Device;
+
+import static org.mockito.Mockito.when;
+
+public class GatorProtocolEncoderTest extends ProtocolTest {
+
+ @Test
+ public void testEncode() throws Exception {
+ var encoder = inject(new GatorProtocolEncoder(null));
+ var device = encoder.getCacheManager().getObject(Device.class, 1);
+ when(device.getUniqueId()).thenReturn("13332082112");
+
+ Command command = new Command();
+ command.setDeviceId(1);
+ command.setType(Command.TYPE_POSITION_SINGLE);
+ verifyCommand(encoder, command, binary("24243000062008958C070D"));
+ }
+}
diff --git a/src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java
index 382c974ce..0f90c9b07 100644
--- a/src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class GenxProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class GenxProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GenxProtocolDecoder(null);
+ var decoder = inject(new GenxProtocolDecoder(null));
decoder.setReportColumns("28,2,3,4,13,17,10,23,27,11,7,8,46,56,59,70,74,75,77,89,90,93,99,107,112,113,114,176,175,178,181,182");
diff --git a/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java
index 50f993839..d835f2f27 100644
--- a/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Gl100ProtocolDecoderTest extends ProtocolTest {
@@ -9,7 +9,7 @@ public class Gl100ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Gl100ProtocolDecoder(null);
+ var decoder = inject(new Gl100ProtocolDecoder(null));
verifyPosition(decoder, text(
"+RESP:GTLGL,359464030492644,1,2,1,0,0.4,0,299.7,1,5.455551,51.449776,20160311083229,0204,0016,03EC,BD94,00,0036,0102090501"));
diff --git a/src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java
index b8ce8af5d..680b3b77c 100644
--- a/src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Gl200BinaryProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Gl200BinaryProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Gl200BinaryProtocolDecoder(null);
+ var decoder = inject(new Gl200BinaryProtocolDecoder(null));
verifyPosition(decoder, binary(
"2b4556542d00fc1fbf0063450102020956325403000343056437f8220700000200000000010000160100f2007eff75a1f0025c6b1a07e1080108241a02680003189c1ac500000000000002100800000000000000000007e1080108241a19e24e4e0d0a"));
diff --git a/src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java
index 17eed8a59..6fd3f0aaa 100644
--- a/src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java
@@ -1,16 +1,16 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class Gl200FrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Gl200FrameDecoder();
+ var decoder = inject(new Gl200FrameDecoder());
assertEquals(
binary("2b4c474e00ff0026fe110b07020106563454040d054905000007e4031911213905083abd0d0a"),
diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java
index 429ee15c7..3f8a4d0c2 100644
--- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,47 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Gl200TextProtocolDecoder(null);
+ var decoder = inject(new Gl200TextProtocolDecoder(null));
+
+ verifyNull(decoder, buffer(
+ "+RESP:GTFRI,8020040200,866314060109269,,,10,1,1,0.0,0,9.0,-71.596601,-33.524595,20230722145338,0730,0001,772A,052B253E,00,0.0,,,,,100,210100,,,,20230722145341,0F4C$"));
+
+ verifyAttributes(decoder, buffer(
+ "+RESP:GTCAN,F1040C,862599050497393,GV350M,0,0,FFFFFFFF,,1,,,,,,,,,,,,,,,,,,,,,,,0,,,1,0.0,70,2961.6,-78.691750,-0.951135,20230703191659,,,,,,20230703191659,5A4A$"));
+
+ verifyAttribute(decoder, buffer(
+ "+RESP:GTBAA,F1040C,862599050497393,GV350M,FF,3,0,04,000A,780541256AE9,3065,0,0.0,213,2908.3,-78.691944,-0.951426,20230511173150,,,,,,20230511175001,0159$"),
+ "accessoryVoltage", 3.065);
+
+ verifyAttribute(decoder, buffer(
+ "+RESP:GTBID,C20105,866833040163013,GV350M,1,0,000A,B80EA11FF800,2934,0,0.0,0,1506.5,-99.192686,18.932709,20221026025339,0334,0020,0232,029D4E02,,20221026181026,9F1D$"),
+ "accessoryVoltage", 2.934);
+
+ verifyAttribute(decoder, buffer(
+ "+RESP:GTDTT,410502,864802030541621,,,,1,35,45637561747261636b0d0a434f4d422c302c39342e302c2d312e302c2c2c4844430d0a,20230421034626,EA2E$"),
+ Position.KEY_FUEL_LEVEL, 94.0);
+
+ verifyNull(decoder, buffer(
+ "+RESP:GTFRI,5E0100,862061048023666,,,12940,10,1,1,0.0,97,179.8,-90.366478,38.735379,20230616183231,0310,0410,6709,03ADF710,00,6223.7,,,,,110000,,,,202306161834$"));
+
+ verifyAttribute(decoder, buffer(
+ "+BUFF:GTERI,410502,864802030794634,,00000001,,10,1,1,0.0,0,3027.8,-78.706612,-0.955699,20230418170736,0740,0002,A08C,2AB72D,00,0.0,,,,100,110000,1,0099,20230418171004,8B98$"),
+ Position.KEY_FUEL_LEVEL, 153);
+
+ verifyPositions(decoder, false, buffer(
+ "+BUFF:GTFRI,2E0503,861106050005423,,,0,1,,,,,,,,,,,,0,0,,98,1,0,,,20200101000001,0083$"));
+
+ verifyAttribute(decoder, buffer(
+ "+RESP:GTERI,271002,863457051562823,,00000002,,10,1,1,0.0,15,28.2,-58.695253,-34.625413,20230119193305,0722,0007,1168,16B3BB,00,0.0,,,,99,210100,2,1,28F8A149F69A3C25,1,0190,20230119193314,07C7$"),
+ Position.PREFIX_TEMP + 1, 25.0);
+
+ verifyAttribute(decoder, buffer(
+ "+RESP:GTDAR,F10406,865284049582228,,4,0,,,1,18.5,0,129.4,114.015430,22.537279,20210922004634,0460,0000,27BD,0DFC,,,,20210922004635,082B$"),
+ "warningType", 4);
+
+ verifyAttribute(decoder, buffer(
+ "+RESP:GTNMR,423033,355197370058831,,0,0,0,1,0,0.0,298,182.7,-79.257983,43.875152,20220627132020,,,,,15,0,74,20220627144928,03CF$"),
+ Position.KEY_BATTERY_LEVEL, 74);
verifyPosition(decoder, buffer(
"+RESP:GTFRI,5E0100,861971050039361,,,,10,1,1,10.4,140,196.9,-80.709946,35.016525,20220302220944,0310,0260,1CE9,52A1,00,0.0,,,,,420000,,,,20220302220948,1B0B$"));
diff --git a/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java
index 3f5296f4b..7391fea28 100644
--- a/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class GlobalSatProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class GlobalSatProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GlobalSatProtocolDecoder(null);
+ var decoder = inject(new GlobalSatProtocolDecoder(null));
verifyNull(decoder, text(
"GSh,131826789036289,3,M,ea04*3d"));
diff --git a/src/test/java/org/traccar/protocol/GlobalSatProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GlobalSatProtocolEncoderTest.java
index ae4b52167..dc00cad44 100644
--- a/src/test/java/org/traccar/protocol/GlobalSatProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/GlobalSatProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class GlobalSatProtocolEncoderTest extends ProtocolTest {
@Test
- public void testEncodeAlarmDismiss() {
+ public void testEncodeAlarmDismiss() throws Exception {
- var encoder = new GlobalSatProtocolEncoder(null);
+ var encoder = inject(new GlobalSatProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -22,9 +22,9 @@ public class GlobalSatProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeOutputControl() {
+ public void testEncodeOutputControl() throws Exception {
- var encoder = new GlobalSatProtocolEncoder(null);
+ var encoder = inject(new GlobalSatProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java
index 1dd5c2542..8d4210e9d 100644
--- a/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
import io.netty.handler.codec.http.HttpMethod;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class GlobalstarProtocolDecoderTest extends ProtocolTest {
@@ -9,7 +9,7 @@ public class GlobalstarProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GlobalstarProtocolDecoder(null);
+ var decoder = inject(new GlobalstarProtocolDecoder(null));
verifyNull(decoder, request(HttpMethod.POST, "/", buffer(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
@@ -29,7 +29,7 @@ public class GlobalstarProtocolDecoderTest extends ProtocolTest {
"<esn>0-2682225</esn>",
"<unixTime>1585105370</unixTime>",
"<gps>N</gps>",
- "<payload length=\"9\" source=\"pc\" encoding=\"hex\">0x8EFE2D97DDEA420018</payload>",
+ "<payload length=\"9\" source=\"pc\" encoding=\"hex\">0x00C583EACD37210A00</payload>",
"</stuMessage>",
"</stuMessages>")));
diff --git a/src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java
index 8bd5e2bd5..78722fa17 100644
--- a/src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class GnxProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class GnxProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GnxProtocolDecoder(null);
+ var decoder = inject(new GnxProtocolDecoder(null));
verifyPosition(decoder, text(
"$GNX_MIF,865733022354161,143,0,172642,180316,172642,180316,1,13.034581,N,080.234521,E,0,05396274,ROUTE_2#########,Deo ############,GNX04008,B0*"));
diff --git a/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java
index bb79f4f25..3e1349a80 100644
--- a/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,11 +9,14 @@ public class GoSafeProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GoSafeProtocolDecoder(null);
+ var decoder = inject(new GoSafeProtocolDecoder(null));
verifyPositions(decoder, false, text(
"*GS06,357330050846344,RST#"));
+ verifyPositions(decoder, text(
+ "*GS06,353218073585128,181255300523,,SYS:Smart Track;V9.31;V1.1.5,GPS:A;5;N31.551856;E74.366920;0;0;;2.15;2.64,COT:0,ADC:10.78;0.02,DTT:4002;E1;0;0;0;1$181325300523,,SYS:Smart Track;V9.31;V1.1.5,GPS:A;6;N31.551856;E74.366920;0;0;;2.05;2.13,COT:0,ADC:10.79;0.02,DTT:4002;E1;0;0;0;1#"));
+
verifyAttribute(decoder, text(
"*GS06,356449068350122,013519070819,,SYS:G6S;V3.37;V1.1.8,GPS:A;12;N23.169866;E113.450728;0;255;54;0.79,COT:18779;,ADC:12.66;0.58,DTT:4084;E1;0;0;0;1,IWD:0;1;ad031652643fff28;23.2;1;1;86031652504fff28;24.3;2;1;e603165252a5ff28;24.2;3;1;bb0416557da6ff28;24.0#"),
Position.PREFIX_TEMP + 3, 24.0);
diff --git a/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java
index bae187959..aea6e7592 100644
--- a/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java
@@ -1,18 +1,30 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
+import org.traccar.model.Position;
public class GotopProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GotopProtocolDecoder(null);
+ var decoder = inject(new GotopProtocolDecoder(null));
verifyNull(decoder, text(
""));
-
+
+ verifyAttribute(decoder, text(
+ "867688033841044,ALM-B1-1,A,DATE:190622,TIME:144956,LAT:22.7193976N,LON:114.3878200E,Speed:000.1,100-22,03.72"),
+ Position.KEY_ALARM, Position.ALARM_GEOFENCE_ENTER);
+
+ verifyAttribute(decoder, text(
+ "860264050778076,CMD-KEY,V,DATE:220516,TIME:090224,LAT:48.7592616N,LON:003.4658121W,Speed:000.0,057-21,01.60"),
+ Position.KEY_ALARM, Position.ALARM_SOS);
+
+ verifyPosition(decoder, text(
+ "860264050778076,CMD-T,A,DATE:220516,TIME:100627,LAT:48.7636978N,LON:003.4652398W,Speed:051.4,077-24,01.00,WIFI:{84-a0-6e-94-42-5e&-47,b2-22-7a-56-5a-2a&-48,b4-b0-24-09-91-d4&-76,18-3c-b7-1f-da-67&-83,08-86-3b-94-78-44&-85,40-24-b2-c5-0f-5e&-87,b0-e5-ed-4e-06-61&-87,60-1d-9d-a6-d2-5d&-88,14-eb-b6-a5-55-8c&-88,40-18-b1-d7-28-54&-88},BLE:{1f-cf-4d-3c-61-bf&-91,39-82-d0-ba-34-69&-57,df-3a-31-ac-ad-72&-73,7c-d9-f4-11-0b-a0&-78,03-b5-9f-45-bd-0d&-88}"));
+
verifyNull(decoder, text(
"353327020412763,CMD-X"));
diff --git a/src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java
index f6524f82b..332423645 100644
--- a/src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java
@@ -1,16 +1,16 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class Gps056FrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Gps056FrameDecoder();
+ var decoder = inject(new Gps056FrameDecoder());
assertEquals(
binary("242435314750534c5f30323836323436323033333738323934361905110f160b0b7710584e1cbd1b9b4500005b100300fb0a071700ffff23"),
diff --git a/src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java
index 01fa98ba4..29cc6b09f 100644
--- a/src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Gps056ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Gps056ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Gps056ProtocolDecoder(null);
+ var decoder = inject(new Gps056ProtocolDecoder(null));
verifyNull(decoder, buffer(
"$$25LOGN_118624620337829462.1#"));
diff --git a/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java
index 79dc8ab7b..c11a5b0d9 100644
--- a/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,11 @@ public class Gps103ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Gps103ProtocolDecoder(null);
+ var decoder = inject(new Gps103ProtocolDecoder(null));
+
+ verifyAttribute(decoder, text(
+ "imei:865456055519122,sensor alarm,2208011920,,L,;"),
+ Position.KEY_ALARM, Position.ALARM_VIBRATION);
verifyPosition(decoder, text(
"imei:864035050002451,tracker,201223064947,,F,064947,A,1935.70640,N,09859.94436,W,0.025,;"));
@@ -155,7 +159,7 @@ public class Gps103ProtocolDecoderTest extends ProtocolTest {
"359586015829802"));
// No GPS signal
- verifyNull(decoder, text(
+ verifyNotNull(decoder, text(
"imei:359586015829802,tracker,000000000,13554900601,L,;"));
verifyPosition(decoder, text(
diff --git a/src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java
index 5edfbf629..3df64039c 100644
--- a/src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class Gps103ProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncodePositionPeriodic() throws Exception {
- var encoder = new Gps103ProtocolEncoder(null);
+ var encoder = inject(new Gps103ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -25,7 +25,7 @@ public class Gps103ProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncodeCustom() throws Exception {
- var encoder = new Gps103ProtocolEncoder(null);
+ var encoder = inject(new Gps103ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java
index c935fb3c2..000163ba8 100644
--- a/src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class GpsGateProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class GpsGateProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GpsGateProtocolDecoder(null);
+ var decoder = inject(new GpsGateProtocolDecoder(null));
verifyPosition(decoder, text(
"$FRCMD,0097,_SendMessage,,7618.51990,S,4002.26182,E,350.0,1.08,0.0,250816,183522.000,0*7F"));
diff --git a/src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java
index c0b4966a8..8a5cb434b 100644
--- a/src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
@@ -9,7 +9,7 @@ public class GpsMarkerProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GpsMarkerProtocolDecoder(null);
+ var decoder = inject(new GpsMarkerProtocolDecoder(null));
verifyPosition(decoder, text(
"$GM23D863071014445404T260816142611N55441051E037325071033063C0530304#"));
diff --git a/src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java
index 7170718f6..73da69d96 100644
--- a/src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class GpsmtaProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class GpsmtaProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GpsmtaProtocolDecoder(null);
+ var decoder = inject(new GpsmtaProtocolDecoder(null));
verifyPosition(decoder, text(
"3085a94ef459 1446536867 49.81621 24.054207 1 0 22 0 10 12 24 0 0"));
diff --git a/src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java b/src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java
index b4e24f961..9d6c189f6 100644
--- a/src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java
@@ -1,16 +1,16 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class GranitFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GranitFrameDecoder();
+ var decoder = inject(new GranitFrameDecoder());
assertEquals(
binary("2b525243427e1a003e2934757c57b8b03c38d279b4e61e9bd7006b000000001c00002a4533"),
diff --git a/src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java
index 7fd5ffe0e..ff45bd99c 100644
--- a/src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class GranitProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class GranitProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GranitProtocolDecoder(null);
+ var decoder = inject(new GranitProtocolDecoder(null));
verifyPositions(decoder, binary(
"2b444441547e8400c500040130050c43495808002839aee3150200000000640000000000000008002839aee3150200000000640000000000000008002839aee3150200000000640000000000000008002839aee3150200000000640000000000000008002839aee3150200000000640000000000000008002839aee3150200000000640000000000000014002a37420d0a"));
diff --git a/src/test/java/org/traccar/protocol/Gs100ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gs100ProtocolDecoderTest.java
index 68c9b8219..c382b3262 100644
--- a/src/test/java/org/traccar/protocol/Gs100ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gs100ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Gs100ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Gs100ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Gs100ProtocolDecoder(null);
+ var decoder = inject(new Gs100ProtocolDecoder(null));
verifyNull(decoder, binary(
"474C490F383632343632303332353036373030133839333831303131363039313838343837323546084657312E302E3236"));
diff --git a/src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java
index 9d36ef346..100ef340a 100644
--- a/src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Gt02ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Gt02ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Gt02ProtocolDecoder(null);
+ var decoder = inject(new Gt02ProtocolDecoder(null));
verifyAttributes(decoder, binary(
"6868150000035889905895258400831c07415045584f4b210d0a"));
diff --git a/src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java
index 059674398..c74427f90 100644
--- a/src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Gt06FrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Gt06FrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Gt06FrameDecoder();
+ var decoder = inject(new Gt06FrameDecoder());
verifyFrame(
binary("787803691604130318491475905BD30E25001E10BBF7635D14759006E626560501CC0028660F213228660F1F2828660EA81E286610731428660F20140D0A"),
diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java
index b65b6709e..9b196e501 100644
--- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Gt06ProtocolDecoder(null);
+ var decoder = inject(new Gt06ProtocolDecoder(null));
verifyNull(decoder, binary(
"787805120099abec0d0a"));
@@ -18,6 +18,78 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest {
"78780D01086471700328358100093F040D0A"));
verifyAttribute(decoder, binary(
+ "78785995ffff01170719152013df0163d45f041ee52018be002f00876900004556454e545f3836323739383035303137353131325f30303030303030305f323032335f30375f32355f31385f33325f30355f31342e6d70340119d15a0d0a"),
+ Position.KEY_EVENT, 0x69);
+
+ verifyAttribute(decoder, binary(
+ "787829a01707150f2d0ecd01635100041e96d000087c02d4020000912e000000000718798d000e0006ed3ce50d0a"),
+ Position.KEY_IGNITION, false);
+
+ verifyNotNull(decoder, binary(
+ "787829a0170704112226cf0163fe7c0420f6f000091302d402000091290000000007186b8f01030001460d010d0a"));
+
+ verifyAttribute(decoder, binary(
+ "797900109b0344373532304136320d0a000f87f00d0a"),
+ Position.KEY_RESULT, "D7520A62");
+
+ verifyAttribute(decoder, binary(
+ "7878241617070a150e24ca01fba0040780e177005c0001720253360027db6204e40400004bf1e90d0a"),
+ Position.KEY_ALARM, Position.ALARM_SOS);
+
+ verifyAttribute(decoder, binary(
+ "78780a130604ea04000006bc8a0d0a"),
+ Position.KEY_POWER, null);
+
+ verifyAttributes(decoder, binary(
+ "797900849404414c4d313d43353b414c4d323d43433b414c4d333d35433b535441313d43303b4459443d30313b534f533d303133323838333730302c2c3b43454e5445523d303133323838333730303b46454e43453d46656e63652c4f46462c302c302e3030303030302c302e3030303030302c3330302c494e206f72204f55542c313b00b79d120d0a"));
+
+ verifyAttribute(decoder, binary(
+ "78782912170316053b3bcf015b51220af1201105d56100000000000000000000869c0130010000000238d1af0d0a"),
+ Position.KEY_DRIVING_TIME, 0);
+
+ verifyAttribute(decoder, binary(
+ "78781219012ed042cc00954d00040419000056fe290d0a"),
+ Position.KEY_ALARM, Position.ALARM_LOW_BATTERY);
+
+ verifyAttribute(decoder, binary(
+ "78782DA4150817073B10CF032EEA9C0B6CE0800015141001CC0100009A00000000000A6F24014605041900FF01908A640D0A"),
+ Position.KEY_ALARM, Position.ALARM_LOW_BATTERY);
+
+ verifyAttribute(decoder, binary(
+ "78782627100419092D07C5027AC91C0C4658000005370900000000000000008002001900FF00004DF60D0A"),
+ Position.KEY_ALARM, Position.ALARM_LOW_BATTERY);
+
+ verifyPosition(decoder, binary(
+ "78781511170103100e1f9904efe30400a97f88003410ffdd000d0a"));
+
+ verifyAttribute(decoder, binary(
+ "787819a5012ed0000075df000000000098661502050413000019a12b0d0a"),
+ Position.KEY_ALARM, Position.ALARM_TAMPERING);
+
+ verifyAttribute(decoder, binary(
+ "7878131302801900002e42016f000000003a0177ef180d0a"),
+ Position.KEY_POWER, 3.67);
+
+ verifyAttribute(decoder, binary(
+ "78782526160913063918c002780fab0c44750f00040008027f14084c0038420600030c020007398e0d0a"),
+ Position.KEY_ALARM, Position.ALARM_TAMPERING);
+
+ verifyAttribute(decoder, binary(
+ "7979000d940516090908081c030defbd2d0d0a"),
+ Position.KEY_DOOR, true);
+
+ verifyAttribute(decoder, binary(
+ "78782516160908063736c0006e70110442fc800000000800000000000000000300002512000473fb0d0a"),
+ Position.KEY_ALARM, Position.ALARM_TAMPERING);
+
+ verifyPosition(decoder, binary(
+ "78782e2416061a103600c80275298404a0a24000184602d4023a49006f060104ed01940000086508004139765000be7d640d0a"));
+
+ verifyAttribute(decoder, binary(
+ "79790019941b524649443a3030384642324245424133390d0a000c14930d0a"),
+ "serial", "RFID:008FB2BEBA39");
+
+ verifyAttribute(decoder, binary(
"7878241216040e102c22cf00915ffb04c6016300195a02d402283b00753f400571040001dda4880d0a"),
Position.KEY_IGNITION, false);
@@ -54,8 +126,9 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest {
"7878281520000000003c49434349443a38393838323339303030303039373330323635303e00020d446f260d0a"),
Position.KEY_ICCID, "89882390000097302650");
- verifyNull(decoder, binary(
- "797900099b0380d600046f91e90d0a"));
+ verifyAttribute(decoder, binary(
+ "797900099b0380d600046f91e90d0a"),
+ Position.KEY_RESULT, "80d600");
verifyNull(decoder, binary(
"797900a56615010d081f3b012c323131303d30303033643238342c323130353d30303030316332302c323130623d30303030326537632c323130633d30303033643238342c323130663d30303030306331632c323130643d30303030323166632c323161363d30303030303030302c323130343d30303030306531302c323132663d30303030303030302c323134353d30303030303030302ccb03851f5f03c020525514a7003e216a0d0a"));
@@ -68,7 +141,7 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest {
verifyAttribute(decoder, binary(
"7979000E9B0332382E33A1E60D0A0289BE490D0A"),
- Position.PREFIX_TEMP + 1, 28.3);
+ Position.KEY_RESULT, "32382e33a1e60d0a");
verifyPosition(decoder, binary(
"7878353714080d05000ac500a886eb0b7522f000100001fe0a05ea004f1b000001002e0400002328003b0217c0003c0401020001002c468a0d0a"));
@@ -111,7 +184,7 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest {
verifyAttribute(decoder, binary(
"797900149b03023539303042343843454238410300139ba40d0a"),
- Position.KEY_DRIVER_UNIQUE_ID, "5900B48CEB");
+ Position.KEY_RESULT, "0235393030423438434542384103");
verifyPosition(decoder, binary(
"787821121303120b2524c70138e363085b549003d43301940057d200cd52c000006aa1ca0d0a"));
@@ -144,7 +217,7 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest {
verifyAttributes(decoder, binary(
"79790008940000ed0289d6860d0a"));
- verifyNull(decoder, binary(
+ verifyAttributes(decoder, binary(
"797900a59404414c4d313d34353b414c4d323d44353b414c4d333d35353b535441313d34303b4459443d30313b534f533d303538353036313536372c2c3b43454e5445523d3b46454e43453d46656e63652c4f46462c302c302e3030303030302c302e3030303030302c3330302c494e206f72204f55542c303b49434349443d38393937313033313031303038393539303432463b4d4f44453d4d4f44452c312c3138303b0008f65e0d0a"));
verifyPosition(decoder, binary(
diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java
index 79165d9dc..80b50df3a 100644
--- a/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -9,7 +9,7 @@ public class Gt06ProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new Gt06ProtocolEncoder(null);
+ var encoder = inject(new Gt06ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java
index 24addc8b4..4d7e8699e 100644
--- a/src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Gt30ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Gt30ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Gt30ProtocolDecoder(null);
+ var decoder = inject(new Gt30ProtocolDecoder(null));
verifyPosition(decoder, text(
"$$005D3037811014 9955102834.000,A,3802.8629,N,02349.7163,E,0.00,,060117,,*13|1.3|26225BD"));
diff --git a/src/test/java/org/traccar/protocol/H02FrameDecoderTest.java b/src/test/java/org/traccar/protocol/H02FrameDecoderTest.java
index 2294b773b..dc6eec84d 100644
--- a/src/test/java/org/traccar/protocol/H02FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/H02FrameDecoderTest.java
@@ -1,16 +1,16 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class H02FrameDecoderTest extends ProtocolTest {
@Test
public void testDecodeShort() throws Exception {
- var decoder = new H02FrameDecoder(0);
+ var decoder = inject(new H02FrameDecoder(0));
assertEquals(
binary("2a48512c3335353438383032303131333931312c56312c3031323934352c412c353233312e37393238332c4e2c30313332342e31303731382c452c302e30352c302c3137303231372c464646464646464623"),
@@ -37,7 +37,7 @@ public class H02FrameDecoderTest extends ProtocolTest {
@Test
public void testDecodeLong() throws Exception {
- var decoder = new H02FrameDecoder(0);
+ var decoder = inject(new H02FrameDecoder(0));
assertEquals(
binary("24410600082621532131081504419390060740418306000000fffffbfdff0015060000002c02dc0c000000001f"),
@@ -48,7 +48,7 @@ public class H02FrameDecoderTest extends ProtocolTest {
@Test
public void testDecodeAlternative() throws Exception {
- var decoder = new H02FrameDecoder(0);
+ var decoder = inject(new H02FrameDecoder(0));
assertEquals(
binary("2a48512c343230363131393133302c4e42522c3130323430332c3233382c312c302c372c313131312c323236342c36332c313131312c323236352c35382c313131312c323236362c35302c313131312c333133352c33372c313131312c3630352c33332c313131312c343932302c33302c313131312c3630372c32382c3131303131372c46464646444646462c3623"),
diff --git a/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java
index ad5f82176..a63488960 100644
--- a/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,10 @@ public class H02ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new H02ProtocolDecoder(null);
+ var decoder = inject(new H02ProtocolDecoder(null));
+
+ verifyPosition(decoder, buffer(
+ "*HQ,3177718238,V6,002926,V,3514.4088,N,9733.2842,W,0.00,0.00,151222,FFF7FBFF,310,260,32936,13641,8944501311217563382F,#"));
verifyPosition(decoder, buffer(
"*HQ,5905101893,V1,105759,A,37573392,S,145037022,E,000.00,173,280122,FF7FFBFF,,,9059e2c,8232,4#"));
@@ -270,7 +273,7 @@ public class H02ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecodeStatus() throws Exception {
- var decoder = new H02ProtocolDecoder(null);
+ var decoder = inject(new H02ProtocolDecoder(null));
verifyAttribute(decoder, buffer(
"*HQ,2705171109,V1,213324,A,5002.5849,N,01433.7822,E,0.00,000,140613,FFFFFFFF#"),
diff --git a/src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java
index 3ed0a7e91..2fc7af958 100644
--- a/src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java
@@ -1,6 +1,7 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -10,14 +11,19 @@ import java.time.LocalTime;
import java.time.ZoneOffset;
import java.util.Date;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class H02ProtocolEncoderTest extends ProtocolTest {
- private H02ProtocolEncoder encoder = new H02ProtocolEncoder(null);
- private Date time = Date.from(
+ private H02ProtocolEncoder encoder;
+ private final Date time = Date.from(
LocalDateTime.of(LocalDate.now(), LocalTime.of(1, 2, 3)).atZone(ZoneOffset.systemDefault()).toInstant());
+ @BeforeEach
+ public void before() throws Exception {
+ encoder = inject(new H02ProtocolEncoder(null));
+ }
+
@Test
public void testAlarmArmEncode() {
diff --git a/src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java
index 9d80940ea..5ad5693be 100644
--- a/src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class HaicomProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class HaicomProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new HaicomProtocolDecoder(null);
+ var decoder = inject(new HaicomProtocolDecoder(null));
verifyPosition(decoder, text(
"$GPRS012497007097169,T100001,150618,230031,5402267400332464,0004,2014,000001,,,1,00#V040*"),
diff --git a/src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java
index 192aa3010..ac814a5f4 100644
--- a/src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class HomtecsProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class HomtecsProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new HomtecsProtocolDecoder(null);
+ var decoder = inject(new HomtecsProtocolDecoder(null));
verifyNull(decoder, text(
"MDS0001_R6d1821f7,170323,143601.00,04,,,,,,,,,"));
diff --git a/src/test/java/org/traccar/protocol/HoopoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HoopoProtocolDecoderTest.java
index 3ee0a5e01..8d57bf787 100644
--- a/src/test/java/org/traccar/protocol/HoopoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HoopoProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class HoopoProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class HoopoProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new HoopoProtocolDecoder(null);
+ var decoder = inject(new HoopoProtocolDecoder(null));
verifyPosition(decoder, text(
"{ \"deviceId\": \"BCCD0654\", \"assetName\": \"BCCD0654\", \"assetType\": \"???? ?????? - ??? 8\", \"eventData\": { \"latitude\": 31.97498, \"longitude\": 34.80802, \"locationName\": \"\", \"accuracyLevel\": \"High\", \"eventType\": \"Arrival\", \"batteryLevel\": 100, \"receiveTime\": \"2021-09-20T18:52:32Z\" }, \"eventTime\": \"2021-09-20T08:52:02Z\", \"serverReportTime\": \"0001-01-01T00:00:00Z\" }"));
diff --git a/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java b/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java
index 228f41ee8..26494f2b9 100644
--- a/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java
@@ -1,16 +1,16 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class HuaShengFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new HuaShengFrameDecoder();
+ var decoder = inject(new HuaShengFrameDecoder());
assertEquals(
binary("c0010c00120060000000000004000600010100c0"),
diff --git a/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java
index 74671b845..d8cc739ab 100644
--- a/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class HuaShengProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new HuaShengProtocolDecoder(null);
+ var decoder = inject(new HuaShengProtocolDecoder(null));
verifyNull(decoder, binary(
"c00000007eaa000000000000cb8000000032313130313030393238323800e9abafffd615d2000000000008000000010015ffffff0000000000000004e7ffffffffff0005000a10080001d5ab000900154b4e4142323531324d4b54353638363630000f00133335343434343131353130333138380014000b00000000000000c0"));
@@ -21,6 +21,13 @@ public class HuaShengProtocolDecoderTest extends ProtocolTest {
"c000000077aa0200000000000e000100143347315f48312e315f56312e30372e54000300133335353835353035303434303635380004000b3531323030303000050005010006000400070004000800050000090018383936313032353431343533333239313833360d000a000f796573696e7465726e6574c0"));
verifyAttribute(decoder, binary(
+ "c0000000bdaa0000000000061d480000083233303132333039323634330000000000000000000000a600140000000100187e02de0a00290372000005951600260000004a0000040009080000004a0005000a0d0000000ad0000900154d414b474d363639484a4e333031383739000f00133836323230353035353338393836320010001031333231322e30303030303000110008000000000014000bf851084f000018001500060000002000153430344030354035363532403130363332c0"),
+ Position.KEY_ODOMETER, 13212000.0);
+
+ verifyNotNull(decoder, binary(
+ "c0000000b9aa00000000000013c800001132333035303431343537323600186bc30045e5b8002a008b0077002d000100187f0c4b2600d906ec000005938800000000000e0000040009110000000e0005000a1d0400000079000900154646464646464646464646464646464646000f00133836323230353035353339313733360010000c302e30303030303000110008000000000014000bf81b204901b52a001500060000002000153231394030324030403130343438393139c0"));
+
+ verifyAttribute(decoder, binary(
"C00000001CAA120000000000020001001001000200030043008200C100C0"),
Position.KEY_DTCS, "P0100 P0200 P0300 C0300 B0200 U0100");
@@ -29,6 +36,9 @@ public class HuaShengProtocolDecoderTest extends ProtocolTest {
Position.KEY_HOURS, 58.7);
verifyNotNull(decoder, binary(
+ "c0000000b1aa000000000000050000000031393730303130313134303200000000000000000000000000000000000100180000000000000000000000000000000000c57e000005000a1a000000c569000900155756575a5a5a43445a4e57313139313534000f00133836393733313035313339393231300010000c302e30303030303000110008000000000014000bf800002800000000150006000000200016353035403031403040313337313931363831c0"));
+
+ verifyNotNull(decoder, binary(
"c000000077aa00000000000070020000003230303132373035313635330000000000000000000000000000000000010015ffffffff000000000000019dffffffffff0005000a1f00000e455a00200019313238354031406666666540386233663930634030000f0013333536373236313038313335343530c0"));
verifyPosition(decoder, binary(
diff --git a/src/test/java/org/traccar/protocol/HuaShengProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/HuaShengProtocolEncoderTest.java
new file mode 100644
index 000000000..c320d4aa9
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/HuaShengProtocolEncoderTest.java
@@ -0,0 +1,33 @@
+package org.traccar.protocol;
+
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+import org.traccar.model.Command;
+
+public class HuaShengProtocolEncoderTest extends ProtocolTest {
+
+ @Test
+ public void testEncode() throws Exception {
+
+ var encoder = inject(new HuaShengProtocolEncoder(null));
+
+ Command command;
+
+ command = new Command();
+ command.setDeviceId(1);
+ command.setType(Command.TYPE_OUTPUT_CONTROL);
+ command.set(Command.KEY_INDEX, 1);
+ command.set(Command.KEY_DATA, "1");
+
+ verifyCommand(encoder, command, binary("c00000000daa1600000000000101c0"));
+
+ command = new Command();
+ command.setDeviceId(1);
+ command.setType(Command.TYPE_POSITION_PERIODIC);
+ command.set(Command.KEY_FREQUENCY, 60);
+
+ verifyCommand(encoder, command, binary("c000000012aa0400000000000100020006003cc0"));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java
index d4789032d..a76beac20 100644
--- a/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class HuabaoFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class HuabaoFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new HuabaoFrameDecoder();
+ var decoder = inject(new HuabaoFrameDecoder());
verifyFrame(
binary("283734303139303331313138352c312c3030312c454c4f434b2c332c35323934333929"),
diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java
index 7aaec33e7..9c3fc164a 100644
--- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,15 +9,81 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new HuabaoProtocolDecoder(null);
+ var decoder = inject(new HuabaoProtocolDecoder(null));
+
+ verifyNull(decoder, binary(
+ "7e010200204f07788ef67601824f4459344f544d314d4459774d4441314d444977626d5633553235536457786cba7e"));
+
+ verifyAttribute(decoder, binary(
+ "7e0200003f014501643822000300020000000c000c0000000000000000000000000000230615143903300111310100530901027f0300456f073e56020900fe02001e57080002000200000000df7e"),
+ Position.KEY_BATTERY_LEVEL, 90);
+
+ verifyAttribute(decoder, binary(
+ "7e090000344f07788ef87d0138f02305151230460102020001ffffffff000100001457000000020006503134353700000c000a029dc63004b99a98230515132726787e"),
+ Position.KEY_DTCS, "P1457");
+
+ verifyAttribute(decoder, binary(
+ "7e0200006476806111898300710000000000100046005d3156065f7128000000000000230511165956660b01fe000001031a5d1a8101670831333231343332326902018b6a01166b01006c0f323034303830393230373533363735711438393434343738383030303030323131303030464b7e"),
+ Position.KEY_BATTERY, 3.95);
+
+ verifyAttribute(decoder, binary(
+ "7e02000071768060874297002d0000000000208022015a30b006c869f8000000000000230505062034600b0004003930303235343939660b01cc0000000c40f89f27b067083133323134333232690201936a01116b01006c0f34363030383138353937303632343071143839383630343938313032313930353835373430607e"),
+ Position.KEY_EVENT, 4);
+
+ verifyAttribute(decoder, binary(
+ "7e0200002f017028775424038d000000000000000a0189dbeb04ca653a00000012014723040700074401040000000030011b31010ee1012dea020001dc7e"),
+ Position.KEY_BATTERY_LEVEL, 45);
+
+ verifyAttribute(decoder, binary(
+ "7E02000079013653183645009E00000000000C0C030158BF0006C926670000004000CE22120904274201040000005DBC3244524956494E47204C4943454E53452454455354244D522E0000000000000000000000000000000000000000000000000000BD0F323431393939393935383030313030E3060000050500007102000C30011F310108987E"),
+ "driver", "DRIVING LICENSE$TEST$MR.");
+
+ verifyAttribute(decoder, binary(
+ "7e55019c3b8571110003399a07032310302029538631031015370500001a0c000000265700440001233703080000001001020202000a0a04028f000af401040c06ff98ffa8007e707e"),
+ "tilt", "[-104,-88,126]");
+
+ verifyPosition(decoder, binary(
+ "7e0900001f4f07788ef87d000cf0230223150215010203013800000c000b029dc58c04b99b60230223171822507e"));
+
+ verifyPosition(decoder, binary(
+ "7e0200004107904226220608ca0000010000000010031dac0d004864f30000000000002212291003220104000179a7300107310100eb17000300e151000300e304000b00d801041edf340000306b007e"));
+
+ verifyPosition(decoder, binary(
+ "7E020000FE069223000241002E00000000000C0003015A98F806C8A1260013000000E622082617464401040000017F02020001030200002504000000002A0200002B0400000000300117310112E306000005890000F3B4000202000000030202F2000402375F00050400000000000602000C000702000C000801320009020072000B020035000C020050000D020176000E0122000F018A00501B4C46504D34414350584731413337303937000000000000000000000052040000000C01000200010101040000000001020200010103040000000101040203E7010C02000E010D020000010E02059B010F020072011002387001110200000112020000011302000001140200000116020000D17E"));
+
+ verifyPositions(decoder, binary(
+ "7E021001A2010036526447000A3B00000000000000010158F52206C916B0000000000000161118110121661D019431000B0000CF47006931000B000058A4006930000B0000882400693B00000000000000010158F52206C916B0000000000000161118110122661D019431000B0000CF47006931000B000058A4006930000B0000882400693B00000000000000010158F52206C916B0000000000000161118110123661D019431000B0000CF47006931000B000058A4006930000B0000882400693B00000000000000010158F52206C916B0000000000000161118110124661D019431000B0000CF47006931000B000058A4006930000B0000882400691C00000000000000010158F52206C916B00000000000001611181101253B00000000000000010158F52206C916B0000000000000161118110126661D019431000B0000CF47006931000B000058A4006930000B0000882400693B00000000000000010158F52206C916B0000000000000161118110127661D019431000B0000CF47006931000B000058A4006930000B0000882400691C00000000000000010158F52206C916B0000000000000161118110128F57E"));
+
+ verifyAttribute(decoder, binary(
+ "7e02000042012291302260198f00000000800c012300d2651605ff3188001e0000000022102510310003020000a70400000000ac040000012ce5020003e60b03bc572900ce2eef183200e7030000005c7e"),
+ Position.PREFIX_TEMP + 3, -17.094117647058823);
+
+ verifyAttribute(decoder, binary(
+ "7E0200008201215233475100030000000000000003015A7F6106CF8CEC003D0000000021071311481901040000005630011931011AE10200755D3D0601CC0024990A7dA0032301CC002499099B2941FC01CC002499099B29430B01CC0024990A7dA0290601CC0024990A7dA015FD01CC0026220994506BFFFE157C010400000001F10C000000000000000000000000997E"),
+ Position.KEY_ALARM, Position.ALARM_ACCELERATION);
+
+ verifyAttribute(decoder, binary(
+ "7e020000340551231425560568000000000400000201618a9706c320e100410000002722060816261501040000015d300115310105eb0a000300e164000300e301957e"),
+ Position.KEY_BATTERY_LEVEL, 100);
verifyNull(decoder, buffer(
"(794104004140,1,001,BASE,2,TIME)"));
+ verifyAttribute(decoder, binary(
+ "7E02000053200002604323004800000000000C00000158B91406CB7007006B00000000220512101138010400000F2803020000250400000000300114310100E30100D50E0100026043232795980277530030E50400000000E7020FC8E8020E83AB7E"),
+ "lock1Locked", false);
+
+ verifyPosition(decoder, binary(
+ "7E0900005A4E5DE66FBA2200C4F02204280610090002010D052B0150052C0400129009052D016B052E014F05300231BA053502000005360203B8053802000005390200AD053D0201EA05440150054604009899D90545040000001E000C00030160A85C06D1C1389C7E"));
+
verifyNull(decoder, binary(
"7E01000021013345678906000F002C012F373031313142534A2D4D3742203030303030303001D4C1423838383838B47E"));
verifyAttribute(decoder, binary(
+ "7E020000480123456789010013000000800000000301597BC506CBFF6600EB00000155210726203531010400000000EB24000C00B28986047701207027150200060089FFFFEFFF0004002D0E10000600C5FFFFFFEF697E"),
+ Position.KEY_ALARM, Position.ALARM_LOW_BATTERY);
+
+ verifyAttribute(decoder, binary(
"7e0200008e01917159043700b300000000800000030158990606ca0fd7000400000000211129111705010400000000cc14383938363037423831303230393031363239363830010d8001aa81021388820200858301148401aa8502189b8601338702007e8801338901148a0200998b1131323334353637383941424344454647488c04000200a88d0200828e0114a00b50353338662c5530323966037e"),
Position.KEY_DTCS, "P538f U029f");
diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java
index 1cb273c2b..87cc2b12e 100644
--- a/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Ignore;
-import org.junit.Test;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
public class HuabaoProtocolEncoderTest extends ProtocolTest {
- @Ignore
+ @Disabled
@Test
public void testEncode() throws Exception {
- var encoder = new HuabaoProtocolEncoder(null);
+ var encoder = inject(new HuabaoProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java
index 81fdae95c..e932ff7e9 100644
--- a/src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class HunterProProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class HunterProProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new HunterProProtocolDecoder(null);
+ var decoder = inject(new HunterProProtocolDecoder(null));
verifyPosition(decoder, text(
">0002<$GPRMC,170559.000,A,0328.3045,N,07630.0735,W,0.73,266.16,200816,,,A77, s000078015180\",0MD"));
diff --git a/src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java
index a5141c389..da4e25fda 100644
--- a/src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class IdplProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class IdplProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new IdplProtocolDecoder(null);
+ var decoder = inject(new IdplProtocolDecoder(null));
verifyPosition(decoder, text(
"*ID1,863071011086474,210314,153218,A,1831.4577,N,07351.1433,E,0.79,240.64,9,20,A,1,4.20,0,1,01,1,0,0,A01,R,935D#"),
diff --git a/src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java
index ee3a25cbe..8de96a890 100644
--- a/src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class IntellitracProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class IntellitracProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new IntellitracProtocolDecoder(null);
+ var decoder = inject(new IntellitracProtocolDecoder(null));
verifyPosition(decoder, text(
"359316075744331,20201008181424,12.014662,57.826301,0,76,24,10,997,3,0,0.000,4.208,20201008181424,0"));
diff --git a/src/test/java/org/traccar/protocol/IotmProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/IotmProtocolDecoderTest.java
index ca72874ef..c4f01fde4 100644
--- a/src/test/java/org/traccar/protocol/IotmProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/IotmProtocolDecoderTest.java
@@ -2,7 +2,7 @@ package org.traccar.protocol;
import io.netty.handler.codec.mqtt.MqttMessageBuilders;
import io.netty.handler.codec.mqtt.MqttQoS;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class IotmProtocolDecoderTest extends ProtocolTest {
@@ -10,7 +10,7 @@ public class IotmProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new IotmProtocolDecoder(null);
+ var decoder = inject(new IotmProtocolDecoder(null));
verifyNull(decoder, MqttMessageBuilders.connect().clientId(
"123456789012345").build());
diff --git a/src/test/java/org/traccar/protocol/ItsFrameDecoderTest.java b/src/test/java/org/traccar/protocol/ItsFrameDecoderTest.java
index 363185b4c..ebdb6fd0f 100644
--- a/src/test/java/org/traccar/protocol/ItsFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ItsFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class ItsFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class ItsFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new ItsFrameDecoder();
+ var decoder = inject(new ItsFrameDecoder());
verifyFrame(
binary("242c2c3836383732383033373731373434312c312e3444335f4149533134305f312e302c56455253494f4e312e302c32382e3633333731372c4e2c37372e3232323730322c45"),
diff --git a/src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java
index dfd86969a..86b438c7c 100644
--- a/src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class ItsProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new ItsProtocolDecoder(null);
+ var decoder = inject(new ItsProtocolDecoder(null));
verifyNull(decoder, text(
"$,LGN,MARK,000000000,358980100077446,V0.0.1,AIS140,19.804487,N,75.225876,E,*"));
diff --git a/src/test/java/org/traccar/protocol/ItsProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/ItsProtocolEncoderTest.java
index 5302709fc..b9bda0c0a 100644
--- a/src/test/java/org/traccar/protocol/ItsProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/ItsProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class ItsProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new ItsProtocolEncoder(null);
+ var encoder = inject(new ItsProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java
index 8a71cb4d5..45655898e 100644
--- a/src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Ivt401ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Ivt401ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Ivt401ProtocolDecoder(null);
+ var decoder = inject(new Ivt401ProtocolDecoder(null));
verifyPosition(decoder, text(
"(TLA,356917051007891,190118,090211,+16.986606,+82.242416,0,66,4,13,1,5,000,00,0.0,11.59,8.30,37.77,0.0,1,1.02,0,0,208,0,0,0,0,000000000,0,0,0,0,0,0,0,1,8654604,5,9,114)"));
diff --git a/src/test/java/org/traccar/protocol/JidoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/JidoProtocolDecoderTest.java
index 9e01d7d68..6b60e19cc 100644
--- a/src/test/java/org/traccar/protocol/JidoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/JidoProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class JidoProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class JidoProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new JidoProtocolDecoder(null);
+ var decoder = inject(new JidoProtocolDecoder(null));
verifyPosition(decoder, text(
"*12345678910101000,01,A,130517,160435,1820.5845,N,07833.2478,E,20,0,067,045,05,28,26,1,075,Y,1,0000,0000,0000,59"));
diff --git a/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java
index 13137006c..c8e29d2ec 100644
--- a/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class JpKorjarProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class JpKorjarProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new JpKorjarProtocolDecoder(null);
+ var decoder = inject(new JpKorjarProtocolDecoder(null));
verifyPosition(decoder, text(
"KORJAR.PL,329587014519383,160910144240,52.247254N,021.013375E,0.00,1,F:4.18V,1 260 01 794B 3517,"));
diff --git a/src/test/java/org/traccar/protocol/JsonFrameDecoderTest.java b/src/test/java/org/traccar/protocol/JsonFrameDecoderTest.java
index 42777e419..f40bcd720 100644
--- a/src/test/java/org/traccar/protocol/JsonFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/JsonFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class JsonFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class JsonFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new JsonFrameDecoder();
+ var decoder = inject(new JsonFrameDecoder());
verifyFrame(
binary("7b226465764964223a2243485a4430384b504430323130343235303436222c2264657654797065223a322c226861726456657273696f6e223a224844545456413139222c226d736754797065223a3131302c2270726f746f636f6c56657273696f6e223a225631222c22736f667456657273696f6e223a22332e312e38222c22737769746368436162537461747573223a2231222c2274786e4e6f223a2231363235323132373431353337227d"),
diff --git a/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java
index eda97ba2d..2dce2309d 100644
--- a/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Jt600FrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,15 @@ public class Jt600FrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Jt600FrameDecoder();
+ var decoder = inject(new Jt600FrameDecoder());
+
+ verifyFrame(
+ binary("2460201102320112003401010000000422434199114158229e000000000009000000000010e06400000000000020100e0868817043592664000000000000"),
+ decoder.decode(null, null, binary("2460201102320112003401010000000422434199114158229e000000000009000000000010e06400000000000020100e0868817043592664000000000000")));
+
+ verifyFrame(
+ binary("24657060730131001b13111710361906538525079524797f000000000000000003f300036c"),
+ decoder.decode(null, null, binary("24657060730131001b13111710361906538525079524797f000000000000000003f300036c")));
verifyFrame(
binary("2480413009781914003406102107544354193631006213423b00000000006c070000000020e064f91ea0671d00020f0f0f0f0f0f0f0f0f0f07f100ea0f6e"),
diff --git a/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java
index 3bf01c1ae..32213fda1 100644
--- a/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java
@@ -1,15 +1,17 @@
package org.traccar.protocol;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import org.junit.Test;
-
public class Jt600ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Jt600ProtocolDecoder(null);
+ var decoder = inject(new Jt600ProtocolDecoder(null));
+
+ verifyPositions(decoder, binary(
+ "2480433966040111002718031919195822424550114158888E15A40000F124080000000000F00F110A24991900000DF0C7"));
verifyPosition(decoder, buffer(
"(8000632862,P45,290322,132412,25.28217,S,57.54683,W,A,0,0,5,0,0000000000,0,0,9,0)"));
diff --git a/src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java
index 51cefb962..5c8c260b7 100644
--- a/src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java
@@ -1,11 +1,11 @@
package org.traccar.protocol;
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
public class Jt600ProtocolEncoderTest extends ProtocolTest {
Jt600ProtocolEncoder encoder = new Jt600ProtocolEncoder(null);
Command command = new Command();
diff --git a/src/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java
index 53ef1d5ca..1425bc066 100755
--- a/src/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class KenjiProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class KenjiProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new KenjiProtocolDecoder(null);
+ var decoder = inject(new KenjiProtocolDecoder(null));
verifyPosition(decoder, text(
">C800000,M005004,O0000,I0002,D124057,A,S3137.2783,W05830.2978,T000.0,H254.3,Y240116,G06*17"),
diff --git a/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java
index 5c2b0732b..7cc65002b 100644
--- a/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java
@@ -1,14 +1,19 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
+import org.traccar.model.Position;
public class KhdProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new KhdProtocolDecoder(null);
+ var decoder = inject(new KhdProtocolDecoder(null));
+
+ verifyAttribute(decoder, binary(
+ "2929a3003e1680ba0a2304180759500000000000000000000000007b00000080001914000000000000000000162001641b0b0000249002bc58030001cc46020000e70d"),
+ Position.KEY_BATTERY_LEVEL, 100);
verifyPosition(decoder, binary(
"2929800028258b8c10210731035840031534240542120200000337fb000000ffff5a00000a0000000005005d0d"));
diff --git a/src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java
index 287d05fca..1ee652cd9 100644
--- a/src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -9,7 +9,7 @@ public class KhdProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new KhdProtocolEncoder(null);
+ var encoder = inject(new KhdProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/L100FrameDecoderTest.java b/src/test/java/org/traccar/protocol/L100FrameDecoderTest.java
index 45c69105b..a9e0a26fe 100644
--- a/src/test/java/org/traccar/protocol/L100FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/L100FrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class L100FrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class L100FrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new L100FrameDecoder();
+ var decoder = inject(new L100FrameDecoder());
verifyFrame(
binary("41544c2c4c2c3836383334353033383137313936332c4e2c3230313231382c3039333031362c412c3032352e3036373134342c4e2c3035352e3134343833332c452c3030302e302c4750532c333933392c3432342c30332c30303430352c303038383334"),
diff --git a/src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java
index d4bef3885..105e1f3f5 100644
--- a/src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class L100ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class L100ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new L100ProtocolDecoder(null);
+ var decoder = inject(new L100ProtocolDecoder(null));
verifyPosition(decoder, text(
"ATL,NP,868004029750174,$GPRMC,062943,A,2533.6719,N,09154.3203,E,0,179,311218,,,*39,#01111011000000,0,0,0,934.82,27.13,4.0,25,405,755,15af,974b,0,0,0,ATL"));
diff --git a/src/test/java/org/traccar/protocol/LacakProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/LacakProtocolDecoderTest.java
index c407d1e64..a8afb8573 100644
--- a/src/test/java/org/traccar/protocol/LacakProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/LacakProtocolDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
import io.netty.handler.codec.http.HttpMethod;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class LacakProtocolDecoderTest extends ProtocolTest {
@@ -9,7 +9,7 @@ public class LacakProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new LacakProtocolDecoder(null);
+ var decoder = inject(new LacakProtocolDecoder(null));
verifyPosition(decoder, request(HttpMethod.POST, "/",
buffer("{\"location\":{\"event\":\"motionchange\",\"is_moving\":false,\"uuid\":\"0e9a2473-a9a7-4c00-997b-fb97d2154e75\",\"timestamp\":\"2021-07-21T08:06:34.444Z\",\"odometer\":0,\"coords\":{\"latitude\":-6.1148096,\"longitude\":106.6837015,\"accuracy\":3.8,\"speed\":18.67,\"speed_accuracy\":0.26,\"heading\":63,\"heading_accuracy\":0.28,\"altitude\":35.7,\"altitude_accuracy\":3.8},\"activity\":{\"type\":\"still\",\"confidence\":100},\"battery\":{\"is_charging\":false,\"level\":0.79},\"extras\":{}},\"device_id\":\"8737767034\"}")));
diff --git a/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java
index 1d5819603..4df486d56 100644
--- a/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class LaipacProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class LaipacProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new LaipacProtocolDecoder(null);
+ var decoder = inject(new LaipacProtocolDecoder(null));
verifyPosition(decoder, text(
"$AVRMC,80006405,212645,r,3013.9938,N,08133.3998,W,0.00,0.00,010317,a,4076,0,1,0,0,53170583,310260*78"));
diff --git a/src/test/java/org/traccar/protocol/LeafSpyProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/LeafSpyProtocolDecoderTest.java
index aed82eb41..dcff59f0c 100644
--- a/src/test/java/org/traccar/protocol/LeafSpyProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/LeafSpyProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class LeafSpyProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class LeafSpyProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new LeafSpyProtocolDecoder(null);
+ var decoder = inject(new LeafSpyProtocolDecoder(null));
verifyNull(decoder, request(
"/?Lat=60.0&Long=30.0"));
diff --git a/src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java
index ede056f96..0ac1ea92f 100644
--- a/src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class M2cProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class M2cProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new M2cProtocolDecoder(null);
+ var decoder = inject(new M2cProtocolDecoder(null));
verifyPositions(decoder, text(
"[#M2C,2020,P1.B1.H3.F9.R1,102,864547034433966,1,L,0,20,171221,062016,28.647552,77.192841,0,0,0.0,0,0,64,255,11983,0,0,0,0.0,0,0,0,404,4,1F6,4D77,31,0*7524\r\n",
diff --git a/src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java
index f318dcfef..c4db6945d 100644
--- a/src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class M2mProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class M2mProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new M2mProtocolDecoder(null);
+ var decoder = inject(new M2mProtocolDecoder(null));
verifyNull(decoder, binary(
"235A3C2A2624215C287D70212A21254C7C6421220B0B0B"));
diff --git a/src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java
index 19f9b9da7..237ef45b5 100644
--- a/src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class MaestroProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class MaestroProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MaestroProtocolDecoder(null);
+ var decoder = inject(new MaestroProtocolDecoder(null));
verifyPosition(decoder, text(
"@353893040202807,705,UPV-02,1,13.2,17,0,0,16/09/11,11:42:49,0.352705,32.647918,1210.5,0.000000,35.33,11,0.8,0.000,0!\0"));
diff --git a/src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java
index 74f3ff1ec..560c7967b 100644
--- a/src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class ManPowerProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class ManPowerProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new ManPowerProtocolDecoder(null);
+ var decoder = inject(new ManPowerProtocolDecoder(null));
verifyPosition(decoder, text(
"simei:352581250259539,,,tracker,51,24,1.73,130426023608,A,3201.5462,N,03452.2975,E,0.01,28B9,1DED,425,01,1x0x0*0x1*60x+2,en-us,"),
diff --git a/src/test/java/org/traccar/protocol/Mavlink2ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Mavlink2ProtocolDecoderTest.java
index ccddb6a11..add137114 100644
--- a/src/test/java/org/traccar/protocol/Mavlink2ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Mavlink2ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Mavlink2ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Mavlink2ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Mavlink2ProtocolDecoder(null);
+ var decoder = inject(new Mavlink2ProtocolDecoder(null));
verifyAttributes(decoder, binary(
"fd1c0000ce01012100004da91f004005d323b89aa30ea6ed070099fb0100f7fffdff0000942c4a88"));
diff --git a/src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java b/src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java
index 19e5cb0ab..996a4c98a 100644
--- a/src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class MegastekFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class MegastekFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MegastekFrameDecoder();
+ var decoder = inject(new MegastekFrameDecoder());
verifyFrame(
binary("30313337244d47563030322c3335343535303035303239323636392c4756543930302c522c3134313231352c3033313830342c412c2c532c2c452c30302c30332c30302c332e36372c302e3030302c302e30302c3131372e312c302e302c3531302c31302c2c2c2c303030302c303030302c32322c31322c302c202c202c2c312d312c39382c5057204f4e3b21"),
diff --git a/src/test/java/org/traccar/protocol/MegastekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MegastekProtocolDecoderTest.java
index 83d62e766..227fb20e0 100644
--- a/src/test/java/org/traccar/protocol/MegastekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MegastekProtocolDecoderTest.java
@@ -1,15 +1,15 @@
package org.traccar.protocol;
-import org.junit.Test;
-import org.traccar.model.Position;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
+import org.traccar.model.Position;
public class MegastekProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MegastekProtocolDecoder(null);
+ var decoder = inject(new MegastekProtocolDecoder(null));
verifyPosition(decoder, text(
"$MGV002,860719020193193,,S,070521,160748,V,2255.09165,N,11404.01322,E,00,00,00,,,,,,,,,,,,,,,,,,,10,015,Restart;!"));
diff --git a/src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java
index c0e5f1e97..2647c49db 100644
--- a/src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
public class MeiligaoFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MeiligaoFrameDecoder();
+ var decoder = inject(new MeiligaoFrameDecoder());
assertNull(
decoder.decode(null, null, binary("00")));
diff --git a/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java
index 087701be4..8074636a3 100644
--- a/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class MeiligaoProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MeiligaoProtocolDecoder(null);
+ var decoder = inject(new MeiligaoProtocolDecoder(null));
verifyAttribute(decoder, binary(
"2424008f142180340967ff99553033333233302e3030302c412c313531362e383039392c4e2c31303435322e383835352c452c302e30302c33332c3038313232302c2c2a33367c302e387c3132337c323130307c303030302c303030302c303230452c303241417c30323038303030353038394530304531434638347c31437c31373243353832437c3042a8060d0a"),
diff --git a/src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java
index 9c50d972a..f62a9f722 100644
--- a/src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -9,7 +9,7 @@ public class MeiligaoProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new MeiligaoProtocolEncoder(null);
+ var encoder = inject(new MeiligaoProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -36,6 +36,10 @@ public class MeiligaoProtocolEncoderTest extends ProtocolTest {
verifyCommand(encoder, command, binary("4040001312345678901234410603e87bb00d0a"));
+ command.setType(Command.TYPE_ENGINE_STOP);
+
+ verifyCommand(encoder, command, binary("4040001212345678901234411501fd460d0a"));
+
}
}
diff --git a/src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java
index 38d0f2f92..f86b676a6 100644
--- a/src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java
@@ -1,16 +1,16 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class MeitrackFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MeitrackFrameDecoder();
+ var decoder = inject(new MeitrackFrameDecoder());
assertEquals(
binary("24244e3132372c3836333037313031333830333036362c4141412c33352c2d312e3330323638302c33362e3835323133352c3135303430393231313032362c412c392c302c302e312c302c352c313635332c343039362c33323634382c3633397c30327c313030347c3930432c303030302c307c307c307c3346467c3330302c2a37430d0a"),
diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java
index 1c90468bd..8d2aee501 100644
--- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,36 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MeitrackProtocolDecoder(null);
+ var decoder = inject(new MeitrackProtocolDecoder(null));
+
+ verifyAttribute(decoder, binary(
+ "2424683136342C3836363334343035333039353238322C4343452C000000000100820018000505000600070B14001500080800000900000A00000B00001606001A0000402300FE90000006022E79570103E55CCC0604E1FDB32B0CC32C00000D58EB02001C01000000050E0CCC010000B627BF11000000004B1001010D475052532847534D2039303029FEA50601FFFFFF7FFFFEA80701010258023800FEB20501010000002A41360D0A"),
+ "battery2Level", 88);
+
+ verifyAttribute(decoder, binary(
+ "2424593434312c3836353431333035303839313733372c4343452c00000000030088001800050501061607191400150008080000098e000a05000b0c001608001a0000402300fe9000000602c3fe5ffe03e22a1f0904e6688d2b0cd94002000d5f6f03001c01000000050e0cf901010032700298c80899ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb205010000000083001700050501061607191400150008080000098e000a05000b0c001608001a0000405100fe9000000502c3fe5ffe03e22a1f0904e6688d2b0cd94002000d606f0300050e0cf901010032700298c80899ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb205010000000088001800050501061607151400150008080000098e000a05000b0c001607001a0000402300fe9000000602c3fe5ffe03e22a1f0904f0688d2b0cd94002000d696f03001c01000000050e0cf901010032700298c80897ff4b16010113464444204c5445284c54452042414e44203329fea50601ffffff7ffffea807024d0000000000feb20501000000002a36320d0a"),
+ Position.KEY_BATTERY_LEVEL, 77);
+
+ verifyAttribute(decoder, binary(
+ "24245b3131342c3836343630363034343939333938372c4343452c0000000001005000130006012305000600070f1b004702060800000900000a00000b0000199d011a00000602d179570103b25ccc0604cf04862b0cc65b01000da4090d001c01000000010e0ccc010000b627be11000000002a41300d0a"),
+ Position.KEY_LOCK, true);
+
+ verifyAttribute(decoder, buffer(
+ "$$u28,864606044993987,D82,0*D6"),
+ Position.KEY_RESULT, "D82,0");
+
+ verifyPositions(decoder, binary(
+ "24245B3139312C3836343630363034343939333938372C4343452C010000000200500013000601250500060007111B00470206080000093E000AE7030B0000199E011A850306028D7A570103F35ACC0604F9D06C2B0CB92E00000D3FA40C00250CA2B900010E0CCC010000B6276313000000004B00120006012A0500060007111B00470206080000093E000AE7030B0000199E011A7C0305028D7A570103F35ACC0604F9D06C2B0CB92E00000D3FA40C00010E0CCC010000B6276313000000002A31340D0A"));
+
+ verifyPositions(decoder, binary(
+ "24246a3138312c3836343238313034313930383330332c4343452c00000000010093001f000505000600070714001502090800000900000a00000b0000160a001706001904001ad90440230006023279570103305ccc0604f536492b0c510300000d495701001c014000000b0e0ccc010000922781abb90c00002a030034212b03008b082c030053082d03009e082e030034212f030034213003003421310300342149090400000000000000004b07010104574946492a36310d0a"));
+
+ verifyPositions(decoder, binary(
+ "2424423233322c3836323039303035303030323831332c4343452c0400000003004400110004050006000700fe6962060800000900000a00000b00001aef044023000602d65fbcfd03173b9c0804cc76ae2a0c14ae1b000d00aa0d001c01000000014b030101003f00100004050006000700fe695f060800000900000a00000b00001aea044016000502d65fbcfd03173b9c0804cf76ae2a0c14ae1b000d03aa0d00014b030101003f00100004050006000700fe695f060800000900000a00000b00001aed044001000502d65fbcfd03173b9c0804d076ae2a0c14ae1b000d04aa0d00014b030101002a30460d0a"));
+
+ verifyAttribute(decoder, buffer(
+ "$$F160,861412043027965,AAA,22,45.499458,-82.493581,220718171428,V,0,0,0,0,0.0,0,227940,119812,302|220|D8D6|086E1B2B,0000,0000|0000|0000|0191|0573,,,3,,002134,0,0*FA"),
+ Position.KEY_POWER, 13.95);
verifyPositions(decoder, binary(
"2424423233392c3836323039303035303030373436352c4343452c0100000003004300130006050006000700140015801b00080800000900000a00000b0000165105198d011a630540160005024c5e910103590bfe0204922153290c6b2501000dd5b50200004300130006050006000700140015011b00080800000900000a00000b0000165005198d011a630540010005024c5e910103590bfe0204932153290c6b2501000dd6b50200004300130006050006000700140015011b00080800000900000a00000b0000165205198d011a630540230005024c5e910103590bfe0204942153290c6b2501000dd7b50200002a43330d0a"));
@@ -122,6 +151,9 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest {
verifyPositions(decoder, binary(
"2424473937302c3336393830303031333436303637342c4343432c020134005b000000010ce304035db9e000ec6f591a000013000000000c001801edb70200c96d0100e60001004838576501000300a101c20400000000010ce304035db9e000ee6f591a000013000000000c001801edb70200ca6d0100e60001004838576501000300a101c20400000000010ce304035db9e000ef6f591a000013000000000c001801edb70200cc6d0100e60001004838576501000300a101c20400000000020ce304035db9e000f76f591a000016000000000c001801edb70200d36d0100e60001004838576502000300a101bf04000000000a0ce304035db9e000f76f591a000016000000000c001801edb70200d46d0100e60001004838576500000300a101bf0400000000020ce304035db9e000fb6f591a000016000000000c001801edb70200d86d0100e60001004838576502000300a101760400000000180ce304035db9e000fc6f591a0000120000000000008c00edb70200d96d0100e60001004838576502000300a10176040000000019b1e2040323b9e0000b70591a0105150600bb0012002901edb70200e76d0100e60001004838576502000300a2017005000000002023e304031fb9e0001070591a010615070027010d001601fcb70200ec6d0100e60001004838576502000300a201800500000000201fe3040302b9e0001170591a010615090019010d001501feb70200ed6d0100e60001004838576502000300a2018005000000002018e30403dcb8e0001270591a0106150b0011010d00150100b80200ee6d0100e60001004838576502000300a2018005000000002036e3040345b8e0001570591a0107150b002d010b0013010ab80200f16d0100e60001004838576502000300a2018005000000002053e3040326b8e0001670591a0107150d0041010b0013010eb80200f26d0100e60001004838576502000300a2018005000000002070e3040310b8e0001770591a0107150e004f010b00130111b80200f36d0100e60001004838576502000300a2018005000000002095e3040306b8e0001870591a0107150d005a010b00140115b80200f46d0100e60001004838576502000300a20180050000000020b3e3040305b8e0001970591a0107150b0060010b00140118b80200f56d0100e60001004838576502000300a20183050000000020cfe3040308b8e0001a70591a0107150b0066010b0014011bb80200f66d0100e60001004838576502000300a20183050000000020eee304030cb8e0001b70591a0106170b0004000d0014011eb80200f76d0100e60001004838576502000300a2018305000000002a62350d0a"));
+ verifyNull(decoder, buffer(
+ "$$z27,861451040910625,AAC,1*D3"));
+
}
}
diff --git a/src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java
index 64fc7e17b..ac9854b8e 100644
--- a/src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class MeitrackProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new MeitrackProtocolEncoder(null);
+ var encoder = inject(new MeitrackProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/MictrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MictrackProtocolDecoderTest.java
index ca8b67a46..3f790d2f9 100644
--- a/src/test/java/org/traccar/protocol/MictrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MictrackProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class MictrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecodeStandard() throws Exception {
- var decoder = new MictrackProtocolDecoder(null);
+ var decoder = inject(new MictrackProtocolDecoder(null));
verifyAttributes(decoder, text(
"MT;5;867035041396795;Y1;220111085741+test,8c:53:c3:db:e7:26,-58,jiuide-842,80:26:89:f0:5e:4f,-74,jiu2ide 403,94:e4:4b:0a:31:08,-75,jiu3ide,7a:91:e9:50:26:0b,-85,CNet-9rNe,78:91:e9:40:26:0b,-87+0+4092+1"));
@@ -48,7 +48,7 @@ public class MictrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecodeLowAltitude() throws Exception {
- var decoder = new MictrackProtocolDecoder(null);
+ var decoder = inject(new MictrackProtocolDecoder(null));
verifyPositions(decoder, text(
"861836051888035$162835.00,A,4139.6460,N,07009.7239,W,,41.53,-25.8,220621"));
diff --git a/src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java
index 69fd82886..d14c020d4 100644
--- a/src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class MilesmateProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class MilesmateProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MilesmateProtocolDecoder(null);
+ var decoder = inject(new MilesmateProtocolDecoder(null));
verifyPosition(decoder, text(
"ApiString={A:861359037373030,B:09.8,C:00.0,D:083506,E:2838.5529N,F:07717.8049E,G:000.00,H:170918,I:G,J:00004100,K:0000000A,L:1234,M:126.86}"));
diff --git a/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java
index 1a9756226..712d59dc9 100644
--- a/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class MiniFinderProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MiniFinderProtocolDecoder(null);
+ var decoder = inject(new MiniFinderProtocolDecoder(null));
verifyNull(decoder, text(
"!1,867273023933661,V07S.5701.1621,100"));
@@ -21,6 +21,10 @@ public class MiniFinderProtocolDecoderTest extends ProtocolTest {
"!1,123456789012345"));
verifyAttribute(decoder, text(
+ "!4,10,040123,,,1.0,110,0,0S,33"),
+ "phone1", "040123");
+
+ verifyAttribute(decoder, text(
"!5,17,V,50"),
Position.KEY_BATTERY_LEVEL, 50);
diff --git a/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java
index 652490b72..f61779a38 100644
--- a/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class MiniFinderProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new MiniFinderProtocolEncoder(null);
+ var encoder = inject(new MiniFinderProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java
index ab23f277a..64d245a8e 100644
--- a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java
@@ -1,22 +1,38 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
+import org.traccar.model.Position;
public class Minifinder2ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Minifinder2ProtocolDecoder(null);
+ var decoder = inject(new Minifinder2ProtocolDecoder(null));
+
+ verifyAttribute(decoder, binary(
+ "ab101c00d6f61e000110013836333932313033393939363038300937efd201640c000000"),
+ "barkCount", 12L);
+
+ verifyAttribute(decoder, binary(
+ "ab00030008c700007f0100"),
+ Position.KEY_RESULT, "0");
+
+ verifyAttribute(decoder, binary(
+ "ab102600080f1400011001383633393231303339393833343736092429b347633003a96409020000008027b34763"),
+ "bark", true);
+
+ verifyPositions(decoder, binary(
+ "AB103D0035A700000110013836373733303035333430333237390924AC5783620103C250162030CC5F0D5002FB432D00AF005A3158006D0A00000B0931EC5783620A000000"));
verifyPositions(decoder, binary(
"ab10350015ae59010110013836333932313033333836353231360924723a12610042535a182ac0f6b4f2923100c900af02215c2b9bfb5461736b4c4d53"));
- verifyNull(decoder, binary(
+ verifyPositions(decoder, false, binary(
"ab10150076f1320003100133353534363530373130323933303602105a"));
- verifyNull(decoder, binary(
+ verifyPositions(decoder, false, binary(
"AB101400594A01000310013836333932323033343437333734350112"));
verifyPositions(decoder, binary(
diff --git a/src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java
new file mode 100644
index 000000000..ef6ff6dd9
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/Minifinder2ProtocolEncoderTest.java
@@ -0,0 +1,29 @@
+package org.traccar.protocol;
+
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+import org.traccar.model.Command;
+import org.traccar.model.Device;
+
+import static org.mockito.Mockito.when;
+
+public class Minifinder2ProtocolEncoderTest extends ProtocolTest {
+
+ @Test
+ public void testEncodeNano() throws Exception {
+
+ var encoder = inject(new Minifinder2ProtocolEncoder(null));
+
+ var device = encoder.getCacheManager().getObject(Device.class, 1);
+ when(device.getModel()).thenReturn("Nano");
+
+ Command command = new Command();
+ command.setDeviceId(1);
+ command.setType(Command.TYPE_FIRMWARE_UPDATE);
+ command.set(Command.KEY_DATA, "https://example.com");
+
+ verifyCommand(encoder, command, binary("ab00160059d2010004143068747470733a2f2f6578616d706c652e636f6d"));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/MobilogixProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MobilogixProtocolDecoderTest.java
index ddfa6ad8b..b6cc2ed77 100644
--- a/src/test/java/org/traccar/protocol/MobilogixProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MobilogixProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class MobilogixProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MobilogixProtocolDecoder(null);
+ var decoder = inject(new MobilogixProtocolDecoder(null));
verifyAttributes(decoder, text(
"[2021-08-20 19:27:14,T14,1,V1.3.5,201909000982,53,12.18"));
diff --git a/src/test/java/org/traccar/protocol/MoovboxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MoovboxProtocolDecoderTest.java
index af19b8222..8e51271b6 100644
--- a/src/test/java/org/traccar/protocol/MoovboxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MoovboxProtocolDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
import io.netty.handler.codec.http.HttpMethod;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class MoovboxProtocolDecoderTest extends ProtocolTest {
@@ -9,7 +9,7 @@ public class MoovboxProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MoovboxProtocolDecoder(null);
+ var decoder = inject(new MoovboxProtocolDecoder(null));
verifyPositions(decoder, request(HttpMethod.POST, "/",
buffer("<gps id=\"911\">\n<coordinates><coordinate>\n<fix>3</fix>\n<time>1597580050</time>\n<latitude>100.726257</latitude>\n<longitude>13.821351</longitude>\n<altitude>9.500000</altitude>\n<climb>0.000000</climb>\n<speed>0.064000</speed>\n<separation>-27.300000</separation>\n<track>0.000000</track>\n<satellites>9</satellites>\n</coordinate></coordinates>\n</gps>")));
diff --git a/src/test/java/org/traccar/protocol/MotorProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MotorProtocolDecoderTest.java
index bd4a97ef4..9de24d87f 100644
--- a/src/test/java/org/traccar/protocol/MotorProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MotorProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class MotorProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class MotorProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MotorProtocolDecoder(null);
+ var decoder = inject(new MotorProtocolDecoder(null));
verifyPosition(decoder, text(
"341200007E7E00007E7E020301803955352401161766210162090501010108191625132655351234567F12345F"));
diff --git a/src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java
index 28b5d3be0..86a72cc2d 100644
--- a/src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class MtxProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class MtxProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MtxProtocolDecoder(null);
+ var decoder = inject(new MtxProtocolDecoder(null));
verifyPosition(decoder, text(
"#MTX,353815011138124,20101226,195550,41.6296399,002.3611174,000,035,000000.00,X,X,1111,000,0,0"));
diff --git a/src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java
index 301b6102b..c1f02f0ae 100644
--- a/src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class MxtProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class MxtProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MxtProtocolDecoder(null);
+ var decoder = inject(new MxtProtocolDecoder(null));
verifyPosition(decoder, binary(
"01a631a7627b00087dc41c40850006aab70affecdf23fd32200080000600000000000000000000001b2ff03b1bb9c4c60214f40100050000006c2d0000f427600051051101de0704"));
diff --git a/src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java
index 60d88999e..5b5865855 100644
--- a/src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class NavigilProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class NavigilProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new NavigilProtocolDecoder(null);
+ var decoder = inject(new NavigilProtocolDecoder(null));
verifyNull(decoder, binary(
"01004300040020000000f60203080200e7cd0f510c0000003b00000000000000"));
diff --git a/src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java b/src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java
index 0ebfeacd2..8678a55ba 100644
--- a/src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java
@@ -1,9 +1,8 @@
package org.traccar.protocol;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import org.junit.Test;
-
public class NavisFrameDecoderTest extends ProtocolTest {
@Test
diff --git a/src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java
index b1282cac7..56f5a4c9f 100644
--- a/src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java
@@ -1,15 +1,14 @@
package org.traccar.protocol;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import org.junit.Test;
-
public class NavisProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecodeNtcb() throws Exception {
- var decoder = new NavisProtocolDecoder(null);
+ var decoder = inject(new NavisProtocolDecoder(null));
verifyNull(decoder, binary(
"404E5443010000007B000000130044342A3E533A383631373835303035323035303739"));
@@ -41,7 +40,7 @@ public class NavisProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecodeFlex10() throws Exception {
- var decoder = new NavisProtocolDecoder(null);
+ var decoder = inject(new NavisProtocolDecoder(null));
verifyNull(decoder, binary(
"404e544301000000c9b5f602130046c52a3e533a383639363936303439373232383235"));
@@ -60,7 +59,7 @@ public class NavisProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecodeFlex20() throws Exception {
- var decoder = new NavisProtocolDecoder(null);
+ var decoder = inject(new NavisProtocolDecoder(null));
verifyNull(decoder, binary(
"404e544301000000a9eef602130043fb2a3e533a383639363936303439373337333835"));
diff --git a/src/test/java/org/traccar/protocol/NavisetFrameDecoderTest.java b/src/test/java/org/traccar/protocol/NavisetFrameDecoderTest.java
index e73c173b7..8f25c2127 100644
--- a/src/test/java/org/traccar/protocol/NavisetFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NavisetFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class NavisetFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class NavisetFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new NavisetFrameDecoder();
+ var decoder = inject(new NavisetFrameDecoder());
verifyFrame(
binary("1310e4073836383230343030353935383436362a060716"),
diff --git a/src/test/java/org/traccar/protocol/NavisetProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NavisetProtocolDecoderTest.java
index df4e57e8d..7722560ca 100644
--- a/src/test/java/org/traccar/protocol/NavisetProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NavisetProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class NavisetProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class NavisetProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new NavisetProtocolDecoder(null);
+ var decoder = inject(new NavisetProtocolDecoder(null));
verifyNull(decoder, binary(
"1310e4073836383230343030353935383436362a060716"));
diff --git a/src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java b/src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java
index 562b220d4..1509472a7 100644
--- a/src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
-import org.junit.Ignore;
-import org.junit.Test;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class NavtelecomFrameDecoderTest extends ProtocolTest {
@@ -9,7 +9,7 @@ public class NavtelecomFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new NavtelecomFrameDecoder();
+ var decoder = inject(new NavtelecomFrameDecoder());
verifyFrame(
binary("404e5443010000000000000013004e452a3e533a383636373935303331343130363839"),
@@ -24,11 +24,11 @@ public class NavtelecomFrameDecoderTest extends ProtocolTest {
}
- @Ignore
+ @Disabled
@Test
public void testDecodeFull() throws Exception {
- var decoder = new NavtelecomFrameDecoder();
+ var decoder = inject(new NavtelecomFrameDecoder());
verifyFrame(
binary("404e5443010000000000000013004e452a3e533a383636373935303331343130363839"),
diff --git a/src/test/java/org/traccar/protocol/NavtelecomProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NavtelecomProtocolDecoderTest.java
index fd22049fc..d715ea596 100644
--- a/src/test/java/org/traccar/protocol/NavtelecomProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NavtelecomProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class NavtelecomProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class NavtelecomProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new NavtelecomProtocolDecoder(null);
+ var decoder = inject(new NavtelecomProtocolDecoder(null));
verifyNull(decoder, binary(
"404e5443010000000000000013004e452a3e533a383636373935303331343130363839"));
diff --git a/src/test/java/org/traccar/protocol/NdtpV6ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NdtpV6ProtocolDecoderTest.java
new file mode 100644
index 000000000..67e88cb5a
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/NdtpV6ProtocolDecoderTest.java
@@ -0,0 +1,18 @@
+package org.traccar.protocol;
+
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+
+public class NdtpV6ProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new NdtpV6ProtocolDecoder(null));
+
+ verifyAttributes(decoder, binary(
+ "7e7e3b000200334202000000000000000064000100000000000600020002034f0c0200000400000000000033353135313330353131393430353532353030323632373237343836363500"));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java
index b77bdf658..841315895 100644
--- a/src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class NeosProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class NeosProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new NeosProtocolDecoder(null);
+ var decoder = inject(new NeosProtocolDecoder(null));
verifyPosition(decoder, text(
">12345678,1,1,070201,144111,W05829.2613,S3435.2313,,00,034,25,00,126-000,0,3,11111111*2d!\r\n"));
diff --git a/src/test/java/org/traccar/protocol/NetProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NetProtocolDecoderTest.java
index 9ab4aea4f..d208b10c5 100644
--- a/src/test/java/org/traccar/protocol/NetProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NetProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class NetProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class NetProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new NetProtocolDecoder(null);
+ var decoder = inject(new NetProtocolDecoder(null));
verifyPosition(decoder, text(
"@L03686090604017761712271020161807037078881037233751000000010F850036980A4000"));
diff --git a/src/test/java/org/traccar/protocol/NiotProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NiotProtocolDecoderTest.java
index 7707094a5..8fa74abd0 100644
--- a/src/test/java/org/traccar/protocol/NiotProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NiotProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class NiotProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class NiotProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new NiotProtocolDecoder(null);
+ var decoder = inject(new NiotProtocolDecoder(null));
verifyPosition(decoder, binary(
"585880004c08675430347318522007161451458024b28003f566ee00000328f8000748217ffc500729007a280000000000160001383932353430323130363431363738373136323100050002004e00570d"),
diff --git a/src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java
index a30847160..3a3461d43 100644
--- a/src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class NoranProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class NoranProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new NoranProtocolDecoder(null);
+ var decoder = inject(new NoranProtocolDecoder(null));
verifyNull(decoder, binary(
"0d0a2a4b57000d000080010d0a"));
diff --git a/src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java
index 76486d024..ddcc02418 100644
--- a/src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -9,7 +9,7 @@ public class NoranProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new NoranProtocolEncoder(null);
+ var encoder = inject(new NoranProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java b/src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java
index 76c7cafb9..d4dcdcc60 100644
--- a/src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java
@@ -1,16 +1,16 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class NvsFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new NvsFrameDecoder();
+ var decoder = inject(new NvsFrameDecoder());
assertEquals(
binary("0012333537303430303630303137383234312e38"),
diff --git a/src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java
index ed4008d47..0c8b41e4a 100644
--- a/src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class NvsProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class NvsProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new NvsProtocolDecoder(null);
+ var decoder = inject(new NvsProtocolDecoder(null));
verifyNull(decoder, binary(
"0012333537303430303630303137383234312e38"));
diff --git a/src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java
index 81de06f89..9dcfe8a78 100644
--- a/src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class NyitechProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class NyitechProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new NyitechProtocolDecoder(null);
+ var decoder = inject(new NyitechProtocolDecoder(null));
verifyPosition(decoder, binary(
"4040690030313436383230303238373201201c0c12031a308080801c0c12031a3007d67e7e08aceb841002000000ae08000000000000000000000000001e002900f0ffdd002700f2ffe0002700f2ffe1002400f0ffdf002400f3ffe3008a00ffff01010000a9c70d0a"));
diff --git a/src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java
index 08ebf9995..53d910ddb 100644
--- a/src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class ObdDongleProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class ObdDongleProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new ObdDongleProtocolDecoder(null);
+ var decoder = inject(new ObdDongleProtocolDecoder(null));
verifyNull(decoder, binary(
"55550003383634383637303232353131303135010009010011023402010201ABAAAA"));
diff --git a/src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java
index 023158f21..4541bf9c0 100644
--- a/src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class OigoProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class OigoProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new OigoProtocolDecoder(null);
+ var decoder = inject(new OigoProtocolDecoder(null));
verifyPosition(decoder, binary(
"7e002e000000146310002523830400001bfb000369150f310c0591594d062ac0c0141508011303cd63101604fd00000000"));
diff --git a/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java
index 0df537642..d3bd4fde4 100644
--- a/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class OkoProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class OkoProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new OkoProtocolDecoder(null);
+ var decoder = inject(new OkoProtocolDecoder(null));
verifyPosition(decoder, text(
"{861001001012919,090745,A,4944.302,N,02353.366,E,0.0,225,251120,7,0.27,F9,11.3,1}"));
diff --git a/src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java b/src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java
index c8bbf399a..1a4365f3c 100644
--- a/src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class OmnicommFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class OmnicommFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new OmnicommFrameDecoder();
+ var decoder = inject(new OmnicommFrameDecoder());
verifyFrame(
binary("c08600004566"),
diff --git a/src/test/java/org/traccar/protocol/OmnicommProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OmnicommProtocolDecoderTest.java
index 76b476fc2..9f509718a 100644
--- a/src/test/java/org/traccar/protocol/OmnicommProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OmnicommProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class OmnicommProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class OmnicommProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new OmnicommProtocolDecoder(null);
+ var decoder = inject(new OmnicommProtocolDecoder(null));
verifyNull(decoder, binary(
"c080080061a61915340100001dec"));
diff --git a/src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java
index 9fbd79cbf..e2db193d1 100644
--- a/src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class OpenGtsProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class OpenGtsProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new OpenGtsProtocolDecoder(null);
+ var decoder = inject(new OpenGtsProtocolDecoder(null));
verifyPosition(decoder, request(
"/?id=999000000000003&gprmc=$GPRMC,082202.0,A,5006.747329,N,01416.512315,E,0.0,,131018,1.2,E,A*2E"));
diff --git a/src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java
index 7d3068c02..21ccfa56d 100644
--- a/src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class OrbcommProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class OrbcommProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new OrbcommProtocolDecoder(null);
+ var decoder = inject(new OrbcommProtocolDecoder(null));
verifyNull(decoder, response(
buffer("{\"ErrorID\":0,\"NextStartUTC\":\"\",\"Messages\":null}")));
diff --git a/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java
index 7368a9d4e..5308568fd 100644
--- a/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class OrionProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class OrionProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new OrionProtocolDecoder(null);
+ var decoder = inject(new OrionProtocolDecoder(null));
verifyPositions(decoder, binary(
"5057000137bf6236235a0331b5c6e402a3b5ecff5102980003000e0c1d172936080e0c1d172936b03b01000882050000008e080000000000008c0300940500000084030085030003067600900113150000000000000000000000000000000000000004a4c8"));
diff --git a/src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java
index a87b45ec4..c779e4c6e 100644
--- a/src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class OsmAndProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class OsmAndProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new OsmAndProtocolDecoder(null);
+ var decoder = inject(new OsmAndProtocolDecoder(null));
verifyNotNull(decoder, request(
"/?id=123456&timestamp=1377177267&cell=257,02,16,2224&cell=257,02,16,2223,-90&wifi=00-14-22-01-23-45,-80&wifi=00-1C-B3-09-85-15,-70"));
diff --git a/src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java
index 1194f7970..7347da0fb 100644
--- a/src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
import io.netty.handler.codec.http.HttpMethod;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class OutsafeProtocolDecoderTest extends ProtocolTest {
@@ -9,7 +9,7 @@ public class OutsafeProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new OutsafeProtocolDecoder(null);
+ var decoder = inject(new OutsafeProtocolDecoder(null));
verifyPosition(decoder, request(HttpMethod.POST, "/",
buffer("{\"device\":\"865303040103725\",\"owner\":\"\",\"data\":{\"cmd\":\"\",\"ms1\":-1,\"ms2\":-1,\"ms3\":0,\"ms4\":0,\"observation\":\"\",\"content\":null},\"time\":1589277568,\"origin\":\"mqgatte\",\"latitude\":19.346855,\"longitude\":-99.29587,\"altitude\":2757,\"heading\":0,\"rssi\":0}")));
diff --git a/src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java
index 55b48fb05..ba0eaec01 100644
--- a/src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
import io.netty.handler.codec.http.HttpMethod;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class OwnTracksProtocolDecoderTest extends ProtocolTest {
@@ -9,7 +9,7 @@ public class OwnTracksProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new OwnTracksProtocolDecoder(null);
+ var decoder = inject(new OwnTracksProtocolDecoder(null));
verifyPosition(decoder, request(HttpMethod.POST, "/",
buffer("{\"_type\":\"location\",\"acc\":15,\"alt\":440,\"batt\":46,\"conn\":\"w\",\"lat\":46.0681247,\"lon\":11.1512805,\"t\":\"u\",\"tid\":\"5t\",\"tst\":1551874878,\"vac\":2,\"vel\":0}")));
diff --git a/src/test/java/org/traccar/protocol/PacificTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PacificTrackProtocolDecoderTest.java
index edf508314..4ae0e6d54 100644
--- a/src/test/java/org/traccar/protocol/PacificTrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PacificTrackProtocolDecoderTest.java
@@ -1,10 +1,10 @@
package org.traccar.protocol;
import io.netty.buffer.Unpooled;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class PacificTrackProtocolDecoderTest extends ProtocolTest {
@@ -22,7 +22,7 @@ public class PacificTrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new PacificTrackProtocolDecoder(null);
+ var decoder = inject(new PacificTrackProtocolDecoder(null));
verifyAttributes(decoder, binary(
"FB80019702808835275309000091108181B2C08F0143000E10000000010000001400010192DF0143288063810A8202835584D285B486E68780882D89C38A788BCE8C3A8D3C8E418F809073A008ACA16600A225A0C0000F4240C10003DF2CC200004E20C3004428C0C4000008C6C5000316A4E011314334424A57464758444C35333137373302A086AB569DFE110E02A8811203FF81000190820100"));
diff --git a/src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java
index e4c9bf449..afd131e95 100644
--- a/src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class PathAwayProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class PathAwayProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new PathAwayProtocolDecoder(null);
+ var decoder = inject(new PathAwayProtocolDecoder(null));
verifyPosition(decoder, request(
"?UserName=name&Password=pass&LOC=$PWS,1,\"Roger\",,,100107,122846,45.317270,-79.642219,45.00,42,1,\"Comment\",0*58"));
diff --git a/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java
index b39060420..cb101fa5f 100644
--- a/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
import io.netty.handler.codec.http.HttpMethod;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class PiligrimProtocolDecoderTest extends ProtocolTest {
@@ -9,12 +9,16 @@ public class PiligrimProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new PiligrimProtocolDecoder(null);
+ var decoder = inject(new PiligrimProtocolDecoder(null));
verifyPositions(decoder, request(HttpMethod.POST,
"/bingps?imei=868204005544720&csq=18&vout=00&vin=4050&dataid=00000000",
binary("fff2200d4110061a32354f3422310062000a0005173b0000a101000300005e00fff2200d4110100932354f2b22310042000b000e173b00009f01000700006000")));
+ verifyPosition(decoder, request(HttpMethod.POST,
+ "/push.do",
+ buffer("&phoneNumber=%2B+78000000000&message=ALARM KEY; $GPRMC,180752.000,A,5314.0857,N,03421.8173,E,0.00,104.74,220722,,,A,V* 29,05; GSM: 250-01 0b54-0519,1c30,3e96,3ebe,412e 25; S; Batt: 405,M")));
+
}
}
diff --git a/src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java
index 2d134d967..59f624eaa 100644
--- a/src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class PluginProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new PluginProtocolDecoder(null);
+ var decoder = inject(new PluginProtocolDecoder(null));
verifyPosition(decoder, text(
"$$STATUS,000000900005,20210521111252,27.171105,-25.600934,62.0,323,0,-1,2,0.000,2147489155,0.00,0,0,0.0,0.0,0,0,0,0,0,0,0,0,0"));
diff --git a/src/test/java/org/traccar/protocol/PolteProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PolteProtocolDecoderTest.java
index 592267b9e..67bac7823 100644
--- a/src/test/java/org/traccar/protocol/PolteProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PolteProtocolDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
import io.netty.handler.codec.http.HttpMethod;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class PolteProtocolDecoderTest extends ProtocolTest {
@@ -9,7 +9,7 @@ public class PolteProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new PolteProtocolDecoder(null);
+ var decoder = inject(new PolteProtocolDecoder(null));
verifyPosition(decoder, request(HttpMethod.POST, "/",
buffer("{\"_id\":\"5f75cf7b02c5023bfc0beaf7\",\"location\":{\"LocationMetrics\":{\"EnvironmentDensity\":1,\"LocationType\":2,\"carrierInfo\":{\"aux\":{\"PLMN\":\"310410\",\"country\":\"United States\",\"name\":\"ATT Wireless Inc\"},\"crs\":{\"PLMN\":\"310410\",\"country\":\"United States\",\"name\":\"ATT Wireless Inc\"}},\"hdop\":1850000,\"leversion\":\"2.2.18-20200729T140651\",\"towercount\":1},\"altitude\":0.0011297669261693954,\"confidence\":783.7972188868215,\"detected_at\":1601556342,\"latitude\":29.77368956725161,\"longitude\":-98.26530342694024,\"towerDB\":\"default\",\"ueToken\":\"ALT12503DE04336CB2E3A4A113FCDE05DF05A6F\",\"uid\":\"WZuDMv5Je\"},\"report\":{\"battery\":{\"count\":555,\"level\":100,\"voltage\":3.52},\"event\":3,\"time\":\"2020-10-01T12:45:48.207Z\"},\"time\":\"2020-10-01T12:45:42Z\",\"ueToken\":\"ALT12503DE04336CB2E3A4A113FCDE05DF05A6F\",\"uid\":\"WZuDMv5Je\"}")));
diff --git a/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java
index 37798d960..c5d57aa25 100644
--- a/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class PortmanProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class PortmanProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new PortmanProtocolDecoder(null);
+ var decoder = inject(new PortmanProtocolDecoder(null));
verifyPosition(decoder, text(
"$EXT,P0RTMANGRANT,A,210609201710,N0951.6879W08357.0129,0,0,NA,NA,11,25,174700.25,NA,01820000,108"));
diff --git a/src/test/java/org/traccar/protocol/PortmanProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/PortmanProtocolEncoderTest.java
index 61f6c4a4e..41e78cf6c 100644
--- a/src/test/java/org/traccar/protocol/PortmanProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/PortmanProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class PortmanProtocolEncoderTest extends ProtocolTest {
@Test
- public void testEncodeEngineStop() {
+ public void testEncodeEngineStop() throws Exception {
- var encoder = new PortmanProtocolEncoder(null);
+ var encoder = inject(new PortmanProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -22,9 +22,9 @@ public class PortmanProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeEngineResume() {
+ public void testEncodeEngineResume() throws Exception {
- var encoder = new PortmanProtocolEncoder(null);
+ var encoder = inject(new PortmanProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java
index 8a4f257f5..ca4d5de07 100644
--- a/src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class PretraceProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class PretraceProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new PretraceProtocolDecoder(null);
+ var decoder = inject(new PretraceProtocolDecoder(null));
verifyPosition(decoder, text(
"(867967021915915U1110A1701201500102238.1700N11401.9324E000264000000000009001790000000,&P11A4,F1050^47"));
diff --git a/src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java
index 403c89e9e..da18441f5 100644
--- a/src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class PretraceProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncodePositionPeriodic() throws Exception {
- var encoder = new PretraceProtocolEncoder(null);
+ var encoder = inject(new PretraceProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -25,7 +25,7 @@ public class PretraceProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncodeCustom() throws Exception {
- var encoder = new PretraceProtocolEncoder(null);
+ var encoder = inject(new PretraceProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java
index a9373e22e..6988f2f72 100644
--- a/src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class PricolProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class PricolProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new PricolProtocolDecoder(null);
+ var decoder = inject(new PricolProtocolDecoder(null));
verifyPosition(decoder, binary(
"3c5052493030303350020000011402110b222b0455152e4e001de819ca450000000000000003820249000000000000000000000000000000000000000040003e"));
diff --git a/src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java
index 6e59f2876..ff205ce35 100644
--- a/src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class ProgressProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class ProgressProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new ProgressProtocolDecoder(null);
+ var decoder = inject(new ProgressProtocolDecoder(null));
verifyNull(decoder, binary(
"020037000100000003003131310f003335343836383035313339303036320f00323530303136333832383531353535010000000100000000000000e6bb97b6"));
diff --git a/src/test/java/org/traccar/protocol/PstFrameDecoderTest.java b/src/test/java/org/traccar/protocol/PstFrameDecoderTest.java
index 96993b97b..45960d783 100644
--- a/src/test/java/org/traccar/protocol/PstFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PstFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class PstFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class PstFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new PstFrameDecoder();
+ var decoder = inject(new PstFrameDecoder());
verifyFrame(
binary("2fafac5a050f0000e0022fafac5a01891e882bbfdd06dd577c9865620a0efe524c419f940b6710f5ba0c86e5868ffc97c77eaaf166a31dba63f9894e98a91b9486c94e79ce537359737a5e9385431a590eb20b5115a2b7939e4e66ae"),
diff --git a/src/test/java/org/traccar/protocol/PstFrameEncoderTest.java b/src/test/java/org/traccar/protocol/PstFrameEncoderTest.java
index bc458c398..bbc17dbea 100644
--- a/src/test/java/org/traccar/protocol/PstFrameEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/PstFrameEncoderTest.java
@@ -2,7 +2,7 @@ package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class PstFrameEncoderTest extends ProtocolTest {
diff --git a/src/test/java/org/traccar/protocol/PstProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PstProtocolDecoderTest.java
index 445c333c1..1fe7d7da4 100644
--- a/src/test/java/org/traccar/protocol/PstProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PstProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class PstProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class PstProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new PstProtocolDecoder(null);
+ var decoder = inject(new PstProtocolDecoder(null));
verifyPosition(decoder, binary(
"2faf97de06000024db0551380cbb08070b040000015a0c09b50177e5100a1822da0d010d0f0451380628101451380cc384b800488a84036901b202d3010001061103ffff00150203523687"));
diff --git a/src/test/java/org/traccar/protocol/PstProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/PstProtocolEncoderTest.java
index abcfa29ec..b6530d815 100644
--- a/src/test/java/org/traccar/protocol/PstProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/PstProtocolEncoderTest.java
@@ -1,15 +1,15 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
public class PstProtocolEncoderTest extends ProtocolTest {
@Test
- public void testEncodeEngineStop() {
+ public void testEncodeEngineStop() throws Exception {
- var encoder = new PstProtocolEncoder(null);
+ var encoder = inject(new PstProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -20,9 +20,9 @@ public class PstProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeEngineResume() {
+ public void testEncodeEngineResume() throws Exception {
- var encoder = new PstProtocolEncoder(null);
+ var encoder = inject(new PstProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/Pt215ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Pt215ProtocolDecoderTest.java
index 24cfd316a..234aff97b 100644
--- a/src/test/java/org/traccar/protocol/Pt215ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Pt215ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Pt215ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Pt215ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Pt215ProtocolDecoder(null);
+ var decoder = inject(new Pt215ProtocolDecoder(null));
verifyNull(decoder, binary(
"58580d010359339075435451010d0a"));
diff --git a/src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java
index 44f57601c..b731b82ad 100644
--- a/src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Pt3000ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Pt3000ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Pt3000ProtocolDecoder(null);
+ var decoder = inject(new Pt3000ProtocolDecoder(null));
verifyPosition(decoder, text(
"%356939010012099,$GPRMC,124945.752,A,4436.6245,N,01054.4634,E,0.11,358.52,060408,,,A,+393334347445,N028d"),
diff --git a/src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java
index 2559ad145..f007dbb18 100644
--- a/src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Pt502FrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Pt502FrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Pt502FrameDecoder();
+ var decoder = inject(new Pt502FrameDecoder());
verifyFrame(
binary("24504844302c3936302cffd8ffdb008400140e0f120f0d14121012171514181e32211e1c1c1e3d2c2e243249404c4b47404645505a736250556d5645466488656d777b8182814e608d978c7d96737e817c011517171e1a1e3b21213b7c5346537c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7cffc000110800f0014003012100021101031101ffdd0004000affc401a20000010501010101010100000000000000000102030405060708090a0b100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9fa0100030101010101010101010000000000000102030405060708090a0b1100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00e5292800ef450020a2800a2801d49400b450014b40052e2800a69340094a05007fffd0e5d14b10055b51b00c76a00527273494005250014500251400525001450015347c25003a928010d25007ffd1e52909a00290d0014b40052d0014500145002e297b50018a280109a6d002d2e2803fffd2e7a04da3777a94fbd0025140052500145002514005250014940054e381400b494008690d007fffd3e4f345001486800a5a005a2800a2801680280168a002909e280100cd028016a48937bfb5007fffd4c5038a42280128a004a280128a003ad2500251400945002a8cb0a9a80133450026692803ffd5e4e8a004a2801694500145002d18a005c5140052e280109a69a0029680140abb147b139eb401ffd6c62290d00251400949400114940052500252d002525003e31c93525002521a004a4a00ffd7e4a8a00281400a29d40094b40053ba500252d0018a31400d3cd250018cd2d005ab58777ccdd074ab645007ffd0c72290d00348a2801280"),
diff --git a/src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java
index a68471c95..2fc9c8073 100644
--- a/src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class Pt502ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Pt502ProtocolDecoder(null);
+ var decoder = inject(new Pt502ProtocolDecoder(null));
verifyNull(decoder, binary(
"24504844302c3936302cffd8ffdb008400140e0f120f0d14121012171514181e32211e1c1c1e3d2c2e243249404c4b47404645505a736250556d5645466488656d777b8182814e608d978c7d96737e817c011517171e1a1e3b21213b7c5346537c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7cffc000110800f0014003012100021101031101ffdd0004000affc401a20000010501010101010100000000000000000102030405060708090a0b100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9fa0100030101010101010101010000000000000102030405060708090a0b1100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00e5292800ef450020a2800a2801d49400b450014b40052e2800a69340094a05007fffd0e5d14b10055b51b00c76a00527273494005250014500251400525001450015347c25003a928010d25007ffd1e52909a00290d0014b40052d0014500145002e297b50018a280109a6d002d2e2803fffd2e7a04da3777a94fbd0025140052500145002514005250014940054e381400b494008690d007fffd3e4f345001486800a5a005a2800a2801680280168a002909e280100cd028016a48937bfb5007fffd4c5038a42280128a004a280128a003ad2500251400945002a8cb0a9a80133450026692803ffd5e4e8a004a2801694500145002d18a005c5140052e280109a69a0029680140abb147b139eb401ffd6c62290d00251400949400114940052500252d002525003e31c93525002521a004a4a00ffd7e4a8a00281400a29d40094b40053ba500252d0018a31400d3cd250018cd2d005ab58777ccdd074ab645007ffd0c72290d00348a2801280"));
diff --git a/src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java
index 62b83c61c..98fe147b2 100644
--- a/src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class Pt502ProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncodeCustom() throws Exception {
- var encoder = new Pt502ProtocolEncoder(null);
+ var encoder = inject(new Pt502ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -25,7 +25,7 @@ public class Pt502ProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncodeOutputControl() throws Exception {
- var encoder = new Pt502ProtocolEncoder(null);
+ var encoder = inject(new Pt502ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -40,7 +40,7 @@ public class Pt502ProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncodeTimezone() throws Exception {
- var encoder = new Pt502ProtocolEncoder(null);
+ var encoder = inject(new Pt502ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -55,7 +55,7 @@ public class Pt502ProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncodeAlarmSpeed() throws Exception {
- var encoder = new Pt502ProtocolEncoder(null);
+ var encoder = inject(new Pt502ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java
index ad987240c..5dca8a0c6 100644
--- a/src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Pt60ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Pt60ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Pt60ProtocolDecoder(null);
+ var decoder = inject(new Pt60ProtocolDecoder(null));
verifyNull(decoder, text(
"@B#@|01|006|864891030184954|9425010450971470|20181213093127|2|1|"));
diff --git a/src/test/java/org/traccar/protocol/R12wProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/R12wProtocolDecoderTest.java
index acb7277b5..4fbc4938e 100644
--- a/src/test/java/org/traccar/protocol/R12wProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/R12wProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class R12wProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class R12wProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new R12wProtocolDecoder(null);
+ var decoder = inject(new R12wProtocolDecoder(null));
verifyNull(decoder, text(
"$HX,0001,860721009104316,e92c,933402042499509,55792760080,12345678,01,a8d940a9,#,50,"));
diff --git a/src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java
index 22902079a..c8ed2269d 100644
--- a/src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class RaceDynamicsProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class RaceDynamicsProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new RaceDynamicsProtocolDecoder(null);
+ var decoder = inject(new RaceDynamicsProtocolDecoder(null));
verifyNull(decoder, text(
"$GPRMC,12,260819,100708,862549040661129,"));
diff --git a/src/test/java/org/traccar/protocol/RadarProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RadarProtocolDecoderTest.java
index be1e4de0b..81fdcfd0b 100644
--- a/src/test/java/org/traccar/protocol/RadarProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RadarProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class RadarProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class RadarProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new RadarProtocolDecoder(null);
+ var decoder = inject(new RadarProtocolDecoder(null));
verifyPositions(decoder, binary(
"361800011459015cb497554c01c101ff003500050038000207ff831c04c01f1c00555cb464895cb46487ff7f04eafeffdbd80000079402ead0000000110000000000120d2aff150000000000000002000a00050002436c61726f0000000000008b00000003764500037653005207ff831c04c01f1c00555cb4648a5cb46489ff7f04eafeffdbd80000079402ead0000000010000000000120e00ff150000000000000002000800060002436c61726f0000000000008d00000003764600037654000207ff831c04c01f1c00555cb464d85cb464d7ff7f04eafeffdbd80000079402ead0000000110000000000120e2aff150000000000000002000700070003436c61726f0000000000008d000000037694000376a2005207ff831c04c01f1c00555cb464d95cb464d9ff7f04eafeffdbd80000079402eac0000000010000000000120e00ff150000000000000002000700070003436c61726f0000000000008d000000037695000376a3000207ff831c04c01f1c00555cb465065cb46504ff7f04eafeffdbd80000079402ead0000000110000000000120e2aff150000000000000000000500060005436c61726f0000000000008d0000000376c2000376d07ed7"));
diff --git a/src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java
index 1b111ee5d..b951ef7b4 100644
--- a/src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class RaveonProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class RaveonProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new RaveonProtocolDecoder(null);
+ var decoder = inject(new RaveonProtocolDecoder(null));
verifyPosition(decoder, text(
"$PRAVE,0001,0001,3308.9051,-11713.1164,195348,1,10,168,31,13.3,3,-83,0,0,,1003.4*66"));
diff --git a/src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java
index 803cfb48a..defc5e8f9 100644
--- a/src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class RecodaProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class RecodaProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new RecodaProtocolDecoder(null);
+ var decoder = inject(new RecodaProtocolDecoder(null));
verifyNull(decoder, binary(
"01100020480000000300000030393535360000000000000001000000303030303000000000000000000000000000000000000000006100004531313037353500ffffffffffff0000"));
diff --git a/src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java
index 4af77cfbf..d27979d1b 100644
--- a/src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class RetranslatorProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class RetranslatorProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new RetranslatorProtocolDecoder(null);
+ var decoder = inject(new RetranslatorProtocolDecoder(null));
verifyPosition(decoder, binary(
"74000000333533393736303133343435343835004B0BFB70000000030BBB000000270102706F73696E666F00A027AFDF5D9848403AC7253383DD4B400000000000805A40003601460B0BBB0000001200047077725F657874002B8716D9CE973B400BBB00000011010361766C5F696E707574730000000001"));
diff --git a/src/test/java/org/traccar/protocol/RfTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RfTrackProtocolDecoderTest.java
new file mode 100644
index 000000000..8073c5459
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/RfTrackProtocolDecoderTest.java
@@ -0,0 +1,19 @@
+package org.traccar.protocol;
+
+import io.netty.handler.codec.http.HttpMethod;
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+
+public class RfTrackProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new RfTrackProtocolDecoder(null));
+
+ verifyPosition(decoder, request(HttpMethod.POST, "/deviceDataUpload.do",
+ buffer("gsm={\"n\":0,\"b\":[{\"l\":6166,\"b\":19,\"c\":21423},{\"l\":6166,\"b\":18,\"c\":21416},{\"l\":6166,\"b\":17,\"c\":21383},{\"l\":6166,\"b\":13,\"c\":21422},{\"l\":6166,\"b\":13,\"c\":21435},{\"l\":6169,\"b\":11,\"c\":21311}],\"c\":460}&wifi=[{\"l\":-49,\"t\":\"lianqin20\",\"m\":\"30-B4-9E-DD-F8-2D\"}]&mt=1073709094&i=358477047125172&gps={\"a\":30.0,\"y\":31.251563,\"s\":4,\"t\":1589764496654,\"z\":0.0,\"x\":121.360346}&dbm=-53&td=1589720501123&rc=0&bar=1001.85065&u_ids=[8441644.1,53036.1]&t=1589764500713&bat=12380&v=T2.142.2_2.0_R03&i_ids=[4247328.1,53036.1,10522408.1]&idt=140736414711817&id=39163")));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java
index e0890a5fc..7fb5f6335 100644
--- a/src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class RitiProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class RitiProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new RitiProtocolDecoder(null);
+ var decoder = inject(new RitiProtocolDecoder(null));
verifyPosition(decoder, binary(
"3b28a2a2056315316d4000008100000000000000005f710000244750524d432c3138303535332e3030302c412c353532342e383437312c4e2c30313133342e313837382c452c302e30302c2c3032313231332c2c2c412a37340d0a00000000000000000000000000000000040404"));
diff --git a/src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java b/src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java
index eaf83458d..f54cf8fcc 100644
--- a/src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class RoboTrackFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class RoboTrackFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new RoboTrackFrameDecoder();
+ var decoder = inject(new RoboTrackFrameDecoder());
verifyFrame(
binary("00524f424f545241434b00000000000000383638323034303032323533343136313233343536373839303132312e313261000000312e353761000000312e3030000000003e"),
diff --git a/src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java
index 40218efdb..5a83ae1b6 100644
--- a/src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class RoboTrackProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class RoboTrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new RoboTrackProtocolDecoder(null);
+ var decoder = inject(new RoboTrackProtocolDecoder(null));
verifyNull(decoder, binary(
"00524f424f545241434b00000000000000383638323034303032323533343136313233343536373839303132312e313261000000312e353761000000312e3030000000003e"));
diff --git a/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java
index 71313e449..13095765b 100644
--- a/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class RstProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new RstProtocolDecoder(null);
+ var decoder = inject(new RstProtocolDecoder(null));
verifyNull(decoder, text(
"RST;A;RST-MINIv2;V7.04;008051261;124;29;04-04-2021 17:27:26;04-04-2021 17:27:26;-1.280811;-47.931755;7353;79;1;14;7315;26;10;0;1855;0;0;0;0;5;5;-1.280821;-47.931747;04-04-2021 17:52:23;6;-1.280863;-47.931770;04-04-2021 18:12:19;5;-1.280844;-47.931763;04-04-2021 17:28:02;5;-1.280900;-47.931770;04-04-2021 19:04:27;4;-1.280843;-47.931747;04-04-2021 18:21:45;04-04-2021 19:29:59;04-04-2021 19:29:59;-1.280770;-47.931595;1;15;0;0;0;0;FIM;"));
diff --git a/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java
index 64ac6a57e..e98dffdef 100644
--- a/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class RuptelaProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,13 @@ public class RuptelaProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new RuptelaProtocolDecoder(null);
+ var decoder = inject(new RuptelaProtocolDecoder(null));
+
+ verifyNull(decoder, binary(
+ "002e000316d53d58d6020f4573303430302e30332e36382e30340000c2b3090d0e950000827b000003e80000003c003c1681"));
+
+ verifyPositions(decoder, false, binary(
+ "03fb0003137ca79f856d01011d386d438b000080000000800000008000ffffffffffff070220211bff011d30c50000386d438b000080000000800000008000ffffffffffff0702201f1bff011d30c30000386d43a9000180000000800000008000ffffffffffffad0320211b16ad01011d30950000386d43c7000080000000800000008000ffffffffffff070220211b00011d30a60000386d4403000080000000800000008000ffffffffffff070220221b00011d30ae0000386d443f000080000000800000008000ffffffffffff070220231b00011d30ae000064c692cb000080000000800000008000ffffffffffff070220231b18011d3091000064c69306000080000000800000008000ffffffffffff070220231b14011d30a7000064c69322000180000000800000008000ffffffffffffad0320241b14ad00011d30a3000064c69342000080000000800000008000ffffffffffff070220241b13011d30ad000064c6934a000180000000800000008000ffffffffffffad0320241b10ad01011d30c3000064c6937e000080000000800000008000ffffffffffff070220241b12011d3092000064c6938b000180000000800000008000ffffffffffffad0320241b12ad00011d30bd000064c69395000180000000800000008000ffffffffffffad0320241b10ad01011d30a6000064c693ba000080000000800000008000ffffffffffff070220251b17011d30a2000064c693d4000180000000800000008000ffffffffffffad0320251b17ad00011d30cc000064c693f6000080000000800000008000ffffffffffff070220251b15011d3090000064c69404000180000000800000008000ffffffffffffad0320251b16ad01011d30a9000064c69432000080000000800000008000ffffffffffff070220261b14011d30be000064c6946d000180000000800000008000ffffffffffffad0320261b15ad00011d30b1000064c6946e000080000000800000008000ffffffffffff070220261b15011d3096000064c694aa000080000000800000008000ffffffffffff070220261b15011d30a8000064c694b2000180000000800000008000ffffffffffffad0320261b15ad01011d30a5000064c694e6000080000000800000008000ffffffffffff070220261b17011d309a000064c694f5000180000000800000008000ffffffffffffad0320261b17ad00011d309c000064c694f6000180000000800000008000ffffffffffffad0320261b17ad01011d3099000064c69522000080000000800000008000ffffffffffff070220261b14011d3094000064c6955e000080000000800000008000ffffffffffff070220261b15011d30b2000064c6959a000080000000800000008000ffffffffffff070220261b14011d30970000ad9e"));
verifyPositions(decoder, binary(
"00800003167d765c155d01000160cd0a310000faae43f7176ee45702332b0c12000006070d05007300cfff260082008600870088000f00d7021100d801c900061d0000c500001e0e988300008900008b000002d0000c9bca720c889a0b047e00000000000000007f0000000000000000800000000000000000810000000000000000a341"));
diff --git a/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java
index 409cd4da5..bb6c098f0 100644
--- a/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -9,7 +9,7 @@ public class RuptelaProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new RuptelaProtocolEncoder(null);
+ var encoder = inject(new RuptelaProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/S168ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/S168ProtocolDecoderTest.java
index ec795c9eb..cebae3ef6 100644
--- a/src/test/java/org/traccar/protocol/S168ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/S168ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class S168ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class S168ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new S168ProtocolDecoder(null);
+ var decoder = inject(new S168ProtocolDecoder(null));
verifyAttributes(decoder, text(
"S168#861118010104168#00ec#0016#SYNC:0093;STATUS:91,51"));
diff --git a/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java b/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java
index ced40acd0..689de29b2 100644
--- a/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java
@@ -1,16 +1,16 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class SabertekFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SabertekFrameDecoder();
+ var decoder = inject(new SabertekFrameDecoder());
assertEquals(
binary("2c3939393939393939392c332c34302c36352c372c302c312c2d32352e3738313636362c32382e3235343730322c34302c3236382c313431342c382c35353632332c"),
diff --git a/src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java
index 148695dcd..b55681ffd 100644
--- a/src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class SabertekProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class SabertekProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SabertekProtocolDecoder(null);
+ var decoder = inject(new SabertekProtocolDecoder(null));
verifyPosition(decoder, text(
",999999999,3,40,65,7,0,1,-25.781666,28.254702,40,268,1414,8,55623,"));
diff --git a/src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java
index 223f4f12f..5e1a24f3b 100644
--- a/src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class SanavProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class SanavProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SanavProtocolDecoder(null);
+ var decoder = inject(new SanavProtocolDecoder(null));
verifyPosition(decoder, text(
"imei=353197040023431&rmc=$GPRMC,015258.000,A,2457.8101,N,12125.5393,E,0.00,0.00,210111,,*18,AUTO,0300,2.1,10,466,97,34E7,3391,74,466,9 7,3F2D,3391,65,466,97,39C9,3391,79,466,97,3F2C,3391,81,466,97,0000,00 00,83,466,97,0000,0000,85,466,97,0000,0000,85,1,24"));
diff --git a/src/test/java/org/traccar/protocol/SanulProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SanulProtocolDecoderTest.java
index 23bd6d80b..f01205155 100644
--- a/src/test/java/org/traccar/protocol/SanulProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SanulProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class SanulProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class SanulProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SanulProtocolDecoder(null);
+ var decoder = inject(new SanulProtocolDecoder(null));
verifyNull(decoder, binary(
"aa007020000100000000000033353333353830313831353431313700000000000000000000"));
diff --git a/src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java
index dcd51063c..c58971d02 100644
--- a/src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class SatsolProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class SatsolProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SatsolProtocolDecoder(null);
+ var decoder = inject(new SatsolProtocolDecoder(null));
verifyPositions(decoder, binary(
"f0e1bf4cb2ec1600e1005f8791e901000000c959515c2cc24a03aeadcd010e01a800250001090201878e92e901000000cb59515c2dc24a03b8adcd018801a8001d0001080201325993e901000000cc59515c2fc24a03bfadcd01ab01a800220001080201dd8194e901000000cd59515c32c24a03ceadcd015801a8002500010802015f3795e905000900ce59515c32c24a03d8adcd01f600a700250001091401000000000000000000863496e901000000cf59515c34c24a03ddadcd019b00a700280001090201714197e904000600cf59515c34c24a03ddadcd019b00a7002800010a1401becd07001901"));
diff --git a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java
index 7e2812714..cc6c17014 100644
--- a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
import io.netty.handler.codec.http.HttpMethod;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -10,7 +10,7 @@ public class SigfoxProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SigfoxProtocolDecoder(null);
+ var decoder = inject(new SigfoxProtocolDecoder(null));
verifyPosition(decoder, request(HttpMethod.POST, "/",
buffer("{ \"device\":\"BFE47E\", \"time\":1590497040, \"data\":\"10297eb01e621122070000be\", \"seqNumber\":8, \"deviceTypeId\":\"5ecb8bfac563d620cc9e6798\", \"ack\":false }")));
diff --git a/src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java
index d264895fc..e599ff36d 100644
--- a/src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class SiwiProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class SiwiProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SiwiProtocolDecoder(null);
+ var decoder = inject(new SiwiProtocolDecoder(null));
verifyPosition(decoder, text(
"$SIWI,868957040831465,44,E,,,1,1,1,16.79,0,0,5,A,17.204447,78.355087,534,44,140955,180221,11,1,15,5,4322,0,0,0,0,0,0,1.0,1.6CPTASF_6.60,0!"));
diff --git a/src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java
index a248056f8..d2bf0f825 100644
--- a/src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class SkypatrolProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class SkypatrolProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SkypatrolProtocolDecoder(null);
+ var decoder = inject(new SkypatrolProtocolDecoder(null));
verifyNull(decoder, binary(
"000a02171101303131373232303031333537393833060200000006202020202020202020312020202020202030313137323230303133353739383320"));
diff --git a/src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java
index 740d1b62c..9bad24865 100644
--- a/src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class SmartSoleProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class SmartSoleProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SmartSoleProtocolDecoder(null);
+ var decoder = inject(new SmartSoleProtocolDecoder(null));
verifyPosition(decoder, text(
"#GTXRP=359366080000385,8,180514200051,34.041981,-118.255806,60,1,1,7,1.80,180514200051,4.16,11"));
diff --git a/src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java
index d806fd790..a8a9223c8 100644
--- a/src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class SmokeyProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class SmokeyProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SmokeyProtocolDecoder(null);
+ var decoder = inject(new SmokeyProtocolDecoder(null));
verifyAttributes(decoder, binary(
"534d0300865101019383025f0403000000000b86250200000c0000028f000102f8cc0900127f08"));
diff --git a/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java
index 7202aaefb..a18c7ee9b 100644
--- a/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class SolarPoweredProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SolarPoweredProtocolDecoder(null);
+ var decoder = inject(new SolarPoweredProtocolDecoder(null));
verifyAttribute(decoder, binary(
"7e850256553309440011003e81131914030600332301a61ed709209ff40014b89082020f0283100000f908000000440000003d1f19021784114161726f6e34475630312d323030333031057e"),
diff --git a/src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java
index 7f8e2b58f..70b645b8f 100644
--- a/src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
import io.netty.handler.codec.http.HttpMethod;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class SpotProtocolDecoderTest extends ProtocolTest {
@@ -9,7 +9,7 @@ public class SpotProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SpotProtocolDecoder(null);
+ var decoder = inject(new SpotProtocolDecoder(null));
verifyPositions(decoder, request(HttpMethod.POST, "/", buffer(
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n",
diff --git a/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java
index 1710ccbb9..f06bb9aac 100644
--- a/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class StarLinkProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new StarLinkProtocolDecoder(null);
+ var decoder = inject(new StarLinkProtocolDecoder(null));
decoder.setFormat("#IMEI#,#EDT#,#PDT#,#LAT#,#LONG#,#SPD#,#IGN#,#ODO#,#DUR#,#TDUR#,#LAC#,#CID#,#VIN#,#VBAT#,#EID#,#EDSC#,#DRV#,#SATU#,#CSS#,#OUT1#,#OUT2#,#CFL#");
diff --git a/src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java
index 851d4eac6..6e2489bfe 100644
--- a/src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class StarcomProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class StarcomProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new StarcomProtocolDecoder(null);
+ var decoder = inject(new StarcomProtocolDecoder(null));
verifyPosition(decoder, text(
"|unit=416307,unittype=5,address=186.167.243.28,kind=14,software_version=14.02.18,hardware_type=17,gps_type=6,longitude=-67.85891,latitude=10.21988,datetime_actual=2019/05/07 21:59:38,network=TCPIP.1|\r\n"));
diff --git a/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java
index 6c2d39940..9b1362f5d 100644
--- a/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,10 +9,19 @@ public class StartekProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new StartekProtocolDecoder(null);
+ var decoder = inject(new StartekProtocolDecoder(null));
- verifyPosition(decoder, text(
- "&&R187,860294046453690,000,0,,220105160656,A,22.994986,72.499711,15,0.9,2,222,55,121135784,404|98|147B|0000376A,24,0000001F,02,00,052E|01A3|0000|0000,1,010000|020000,,853|6|10|105|73|41|125|34|52"));
+ verifyAttribute(decoder, text(
+ "&&s148,868703050178631,000,37,,230704040211,A,22.678565,114.046011,31,0.5,0,339,77,8,460|0|249F|0AC2620D,27,0000001D,02,00,04F2|01A1|0000|0000,129,,,,949037"),
+ Position.KEY_HOURS, 9490000L);
+
+ verifyAttribute(decoder, text(
+ "&&x164,869926040743375,000,0,,220705205955,A,33.326001,44.445318,10,1.2,0,57,8,925,418|40|038C|000083CD,31,00000015,00,00,0016|016A|0000|0000,1,,,686|33||44|99|14|124|11|8D"),
+ Position.KEY_FUEL_CONSUMPTION, 1.1);
+
+ verifyAttribute(decoder, text(
+ "&&R187,860294046453690,000,0,,220105160656,A,22.994986,72.499711,15,0.9,2,222,55,121135784,404|98|147B|0000376A,24,0000001F,02,00,052E|01A3|0000|0000,1,010000|020000,,853|6|10|105|73|41|125|34|52"),
+ Position.KEY_FUEL_LEVEL, null);
verifyPosition(decoder, text(
"&&o142,860262050066062,000,27,,211111070826,V,28.653435,-106.077455,0,0.0,0,151,1412,918,0|0|4708|01402D19,6,0000001A,02,00,04C0|016C|0000|0000,1,,,BB"));
diff --git a/src/test/java/org/traccar/protocol/StartekProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/StartekProtocolEncoderTest.java
index 7eeb19edf..c87e421f2 100644
--- a/src/test/java/org/traccar/protocol/StartekProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/StartekProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class StartekProtocolEncoderTest extends ProtocolTest {
@Test
- public void testEncodeEngineStop() {
+ public void testEncodeEngineStop() throws Exception {
- var encoder = new StartekProtocolEncoder(null);
+ var encoder = inject(new StartekProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/StbProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/StbProtocolDecoderTest.java
index 74b30f9eb..dbdeee4d7 100644
--- a/src/test/java/org/traccar/protocol/StbProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/StbProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class StbProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class StbProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new StbProtocolDecoder(null);
+ var decoder = inject(new StbProtocolDecoder(null));
verifyAttributes(decoder, text(
"{\"attrList\":[{\"id\":\"02101001\",\"value\":\"510101051161205774\"},{\"id\":\"02105001\",\"value\":\"-61\"},{\"id\":\"02102001\",\"value\":\"1\"},{\"doorId\":\"1\",\"id\":\"02104001\",\"value\":\"0\"},{\"doorId\":\"1\",\"id\":\"02106001\",\"value\":\"\"},{\"doorId\":\"1\",\"id\":\"02103001\",\"value\":\"0\"},{\"doorId\":\"1\",\"id\":\"02118001\",\"value\":\"1\"},{\"doorId\":\"2\",\"id\":\"02104001\",\"value\":\"0\"},{\"doorId\":\"2\",\"id\":\"02106001\",\"value\":\"\"},{\"doorId\":\"2\",\"id\":\"02103001\",\"value\":\"0\"},{\"doorId\":\"2\",\"id\":\"02118001\",\"value\":\"1\"},{\"doorId\":\"3\",\"id\":\"02104001\",\"value\":\"0\"},{\"doorId\":\"3\",\"id\":\"02106001\",\"value\":\"\"},{\"doorId\":\"3\",\"id\":\"02103001\",\"value\":\"0\"},{\"doorId\":\"3\",\"id\":\"02118001\",\"value\":\"1\"},{\"doorId\":\"4\",\"id\":\"02104001\",\"value\":\"0\"},{\"doorId\":\"4\",\"id\":\"02106001\",\"value\":\"\"},{\"doorId\":\"4\",\"id\":\"02103001\",\"value\":\"0\"},{\"doorId\":\"4\",\"id\":\"02118001\",\"value\":\"1\"},{\"doorId\":\"5\",\"id\":\"02104001\",\"value\":\"0\"},{\"doorId\":\"5\",\"id\":\"02106001\",\"value\":\"\"},{\"doorId\":\"5\",\"id\":\"02103001\",\"value\":\"1\"},{\"doorId\":\"5\",\"id\":\"02118001\",\"value\":\"1\"},{\"doorId\":\"6\",\"id\":\"02104001\",\"value\":\"2\"},{\"doorId\":\"6\",\"id\":\"02106001\",\"value\":\"BT106002320JPZZ210718002\"},{\"doorId\":\"6\",\"id\":\"02109001\",\"value\":\"98\"},{\"doorId\":\"6\",\"id\":\"02110001\",\"value\":\"100\"},{\"doorId\":\"6\",\"id\":\"01118001\",\"value\":\"27\"},{\"doorId\":\"6\",\"id\":\"01119001\",\"value\":\"26\"},{\"doorId\":\"6\",\"id\":\"01120001\",\"value\":\"28\"},{\"doorId\":\"6\",\"id\":\"02114001\",\"value\":\"0\"},{\"doorId\":\"6\",\"id\":\"02116001\",\"value\":\"0\"},{\"doorId\":\"6\",\"id\":\"02117001\",\"value\":\"0\"},{\"doorId\":\"6\",\"id\":\"01121001\",\"value\":\"2\"},{\"doorId\":\"6\",\"id\":\"02130001\",\"value\":\"0\"},{\"doorId\":\"6\",\"id\":\"01122001\",\"value\":\"4\"},{\"doorId\":\"6\",\"id\":\"02001001\",\"value\":\"000\"},{\"doorId\":\"6\",\"id\":\"02002001\",\"value\":\"000\"},{\"doorId\":\"6\",\"id\":\"01116001\",\"value\":\"20\"},{\"doorId\":\"6\",\"id\":\"01117001\",\"value\":\"3323\"},{\"doorId\":\"6\",\"id\":\"01117002\",\"value\":\"3324\"},{\"doorId\":\"6\",\"id\":\"01117003\",\"value\":\"3323\"},{\"doorId\":\"6\",\"id\":\"01117004\",\"value\":\"3324\"},{\"doorId\":\"6\",\"id\":\"01117005\",\"value\":\"3323\"},{\"doorId\":\"6\",\"id\":\"01117006\",\"value\":\"3324\"},{\"doorId\":\"6\",\"id\":\"01117007\",\"value\":\"3325\"},{\"doorId\":\"6\",\"id\":\"01117008\",\"value\":\"3324\"},{\"doorId\":\"6\",\"id\":\"01117009\",\"value\":\"3325\"},{\"doorId\":\"6\",\"id\":\"01117010\",\"value\":\"3326\"},{\"doorId\":\"6\",\"id\":\"01117011\",\"value\":\"3326\"},{\"doorId\":\"6\",\"id\":\"01117012\",\"value\":\"3324\"},{\"doorId\":\"6\",\"id\":\"01117013\",\"value\":\"3324\"},{\"doorId\":\"6\",\"id\":\"01117014\",\"value\":\"3323\"},{\"doorId\":\"6\",\"id\":\"01117015\",\"value\":\"3324\"},{\"doorId\":\"6\",\"id\":\"01117016\",\"value\":\"3324\"},{\"doorId\":\"6\",\"id\":\"01117017\",\"value\":\"3323\"},{\"doorId\":\"6\",\"id\":\"01117018\",\"value\":\"3323\"},{\"doorId\":\"6\",\"id\":\"01117019\",\"value\":\"3324\"},{\"doorId\":\"6\",\"id\":\"01117020\",\"value\":\"3323\"},{\"batteryId\":\"BT106002320JPZZ210718002\",\"doorId\":\"6\",\"id\":\"02103001\",\"value\":\"1\"},{\"batteryId\":\"BT106002320JPZZ210718002\",\"doorId\":\"6\",\"id\":\"02118001\",\"value\":\"1\"},{\"doorId\":\"7\",\"id\":\"02104001\",\"value\":\"0\"},{\"doorId\":\"7\",\"id\":\"02106001\",\"value\":\"\"},{\"doorId\":\"7\",\"id\":\"02103001\",\"value\":\"1\"},{\"doorId\":\"7\",\"id\":\"02118001\",\"value\":\"1\"},{\"doorId\":\"8\",\"id\":\"02104001\",\"value\":\"0\"},{\"doorId\":\"8\",\"id\":\"02106001\",\"value\":\"\"},{\"doorId\":\"8\",\"id\":\"02103001\",\"value\":\"0\"},{\"doorId\":\"8\",\"id\":\"02118001\",\"value\":\"1\"},{\"id\":\"02111001\",\"value\":\"0.0\"},{\"id\":\"02112001\",\"value\":\"0.0\"},{\"id\":\"02107001\",\"value\":\"229.1\"},{\"id\":\"02108001\",\"value\":\"1.005\"},{\"id\":\"02120001\",\"value\":\"143.76\"},{\"id\":\"02113001\",\"value\":\"29\"},{\"id\":\"02119001\",\"value\":\"1\"}],\"devId\":\"CHZD08KPD0210425046\",\"isFull\":1,\"msgType\":310,\"txnNo\":\"1636707944778\"}"));
diff --git a/src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java
index e13f74604..353fe4317 100644
--- a/src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Stl060ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Stl060ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Stl060ProtocolDecoder(null);
+ var decoder = inject(new Stl060ProtocolDecoder(null));
verifyPosition(decoder, text(
"$1,357804048043099,D001,AP29AW0963,23/02/14,14:06:54,17248488N,078342226E,0.08,193.12,1,1,1,1,1,A"),
diff --git a/src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java b/src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java
index 99cbeac2f..0db6e756c 100644
--- a/src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class SuntechFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,11 @@ public class SuntechFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SuntechFrameDecoder();
+ var decoder = inject(new SuntechFrameDecoder());
+
+ verifyFrame(
+ binary("53543330305545583b3531313639393339383b34353b3331353b32303232303632333b31383a32343a35383b3661313332393b2d32392e3735343934373b2d3035372e3038353838353b3030302e3030303b3030302e30303b31303b313b37323b302e30303b3030303030303b31323b0201100110011090011001100110011001100110fe3b39303b3030303030303b332e393b313b30303030303030303030303030303b30"),
+ decoder.decode(null, null, binary("53543330305545583b3531313639393339383b34353b3331353b32303232303632333b31383a32343a35383b3661313332393b2d32392e3735343934373b2d3035372e3038353838353b3030302e3030303b3030302e30303b31303b313b37323b302e30303b3030303030303b31323b0201100110011090011001100110011001100110fe3b39303b3030303030303b332e393b313b30303030303030303030303030303b300d")));
verifyFrame(
binary("81004e05200013383fffff3401000301130a0512080400000000000000000000000047f9d5846a06810072225214010100020300a8002604c1000004b000000470000025a100000000000025c4000000a6"),
diff --git a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java
index 098758728..cbb68132f 100644
--- a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java
@@ -1,87 +1,30 @@
package org.traccar.protocol;
-import org.junit.Ignore;
-import org.junit.Test;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
public class SuntechProtocolDecoderTest extends ProtocolTest {
@Test
- public void testDecodeTemperature() throws Exception {
-
- var decoder = new SuntechProtocolDecoder(null);
-
- decoder.setHbm(true);
- decoder.setIncludeAdc(true);
-
- verifyAttribute(decoder, buffer(
- "ST600STT;008594432;20;492;20200212;18:58:30;060bb0e1;334;20;36bb;45;+19.337897;-099.064489;000.398;000.00;12;1;5049883;13.61;100100;2;1198;013762;4.2;1;4.68"),
- Position.PREFIX_ADC + 1, 4.68);
-
- decoder.setIncludeTemp(true);
+ public void testDecode() throws Exception {
- verifyAttribute(decoder, buffer(
- "ST600STT;008350848;35;523;20191102;13:49:46;0bf14fdb;334;20;2f19;57;+20.466737;-100.825455;000.006;000.00;11;1;10274175;11.36;00000000;1;0300;018353;4.2;1;0.00;;;;00000000000000;0;28EE56B911160234:+13.7;:;:"),
- Position.PREFIX_TEMP + 2, 13.7);
+ var decoder = inject(new SuntechProtocolDecoder(null));
- verifyPosition(decoder, buffer(
- "ST300STT;205173382;07;564;20160322;23:23:18;232e19;+19.288278;-099.128750;000.122;000.00;9;1;478391;11.53;000100;1;9498;079324;4.3;1;0.00;0.00;0.00;00000000000000;0;2898E16006000058:-20.8;2861626006000039:+2.5;:"));
+ verifyAttributes(decoder, buffer(
+ "ST410STT;109815653;445;03;16531;724;10;-77;6011;7;16273;724;10;7511;0;0;13903;724;10;6011;0;0;7671;724;10;7111;0;0;16533;724;10;6011;0;0;0;0;0;0;0;0;0;0;0;0;0;0;3.86;0;0098;1;003;;;;;;;;;"));
verifyPosition(decoder, buffer(
- "ST300EVT;205173382;07;564;20160322;23:23:18;232e19;+19.288278;-099.128750;000.122;000.00;9;1;478391;11.53;000100;2;1;9498;079324;4.3;1;0.00;0.00;0.00;00000000000000;0;2898E16006000058:-20.8;2861626006000039:+2.5;:"));
-
- verifyPosition(decoder, buffer(
- "ST600STT;008349958;35;523;20181112;00:49:30;0bf10d4e;334;20;2f19;22;+20.552718;-100.824478;050.021;095.41;12;1;1303603;14.30;10000000;4;8911;001987;4.1;0;0.00;;;;00000000000000;0;2826C8A70800000C:+26.6;:;:"));
-
- }
-
- @Test
- public void testDecodeRpm() throws Exception {
-
- var decoder = new SuntechProtocolDecoder(null);
-
- decoder.setHbm(true);
- decoder.setIncludeRpm(true);
+ "ALT;0840037569;FFFFFF;84;1.0.6;0;20221228;11:33:05;00004490;724;11;05D3;33;-22.845935;-46.322000;0.00;0.00;18;0;00000001;00000000;99;;;;08E3800F;4.1;12.37;0;0;0;0;4;;;;"));
verifyAttribute(decoder, buffer(
- "ST300STT;907131077;04;706;20190227;23:59:34;cc719;-12.963490;-038.499587;000.067;000.00;7;1;57095;12.50;000000;1;0337;000207;0.0;1;0;012E717F010000;1"),
- Position.KEY_RPM, 0);
-
- }
-
- @Test
- public void testDecodeHours() throws Exception {
-
- var decoder = new SuntechProtocolDecoder(null);
-
- decoder.setHbm(true);
-
- verifyAttribute(decoder, buffer(
- "ST300ALT;007239104;40;313;20190112;01:07:16;c99139;+04.703287;-074.148897;000.000;189.72;21;1;425512;12.61;100000;33;003188;4.1;1"),
- Position.KEY_HOURS, 3188 * 60000L);
-
- }
-
- @Test
- public void testDecodeDriver() throws Exception {
-
- var decoder = new SuntechProtocolDecoder(null);
+ "ALT;0950030205;3FFFFF;95;1.0.11;0;20221017;21:41:30;02F2F402;334;20;0F1D;45;+25.791061;-100.170745;0.00;0.00;18;1;00000101;00000000;42;2;"),
+ Position.KEY_ALARM, Position.ALARM_SOS);
verifyAttribute(decoder, buffer(
- "ST300HTE;511050566;45;308;20200909;13:38:38;0;12.50;001354;0.0;1;0;1;1;0;-27.636632;-052.277933;-27.636675;-052.277947;000.000;002.296;0;00000000000000"),
- Position.KEY_DRIVER_UNIQUE_ID, "00000000000000");
-
- verifyAttribute(decoder, buffer(
- "ST300HTE;100850001;04;248;20110101;00:13:52;167559;12.28;004005;0.0;1;0;3;3;0;-22.881018;-047.070831;-22.881018;-047.070831;000.000;000.000;0;0;3;0;0;0;01E04D44160000"),
- Position.KEY_DRIVER_UNIQUE_ID, "01E04D44160000");
-
- }
-
- @Test
- public void testDecode() throws Exception {
-
- var decoder = new SuntechProtocolDecoder(null);
+ "RES;4309999001;04;02;TEST"),
+ Position.KEY_RESULT, "04;02;TEST");
verifyPosition(decoder, buffer(
"BLE;1140000053;114;1.0.1;20211001;17:27:09;+28.433465;-82.565891;1;-43;-46;-41;ACB89523EF68;247;0;0"));
@@ -92,6 +35,17 @@ public class SuntechProtocolDecoderTest extends ProtocolTest {
verifyNull(decoder, buffer(
"BSA;0820012345;001FFF;82;1.0.0;1;20191203;17:00:51;+32.691615;-117.297160;1;-55;68:11:6A:FD:1A:A7;6AA5;1DE8"));
+ verifyAttributes(decoder, binary(
+ "53543330305545583b3531313639393339383b34353b3331353b32303232303632333b31383a32343a35383b3661313332393b2d32392e3735343934373b2d3035372e3038353838353b3030302e3030303b3030302e30303b31303b313b37323b302e30303b3030303030303b31323b0201100110011090011001100110011001100110fe3b39303b3030303030303b332e393b313b30303030303030303030303030303b30"));
+
+ verifyAttribute(decoder, buffer(
+ "ST300UEX;511248287;45;311;20220701;18:42:08;14c943;-22.975257;-043.373065;000.000;000.00;0;0;0;12.14;100010;19;RFID:008FB2BEBA39\r\n;3E;000135;4.1;1;00000000000000;0"),
+ "serial", "RFID:008FB2BEBA39");
+
+ verifyAttribute(decoder, buffer(
+ "ST300UEX;100850000;01;010;20081017;07:41:56;2F100;+37.478519;+126.886819;000.012;000.00;9;1;0;15.30;001100;25;Welcome to Suntech World!;12;0;4.5;1"),
+ "serial", "Welcome to Suntech World!");
+
verifyAttribute(decoder, buffer(
"ST300UEX;511331307;45;311;20210420;12:41:01;12361;-01.280825;-047.931773;000.000;000.00;16;1;0;12.54;000000;23;GTSL|6|1|0|9255143|2|;6F;000276;0.0;1;00000000000000;0"),
Position.KEY_DRIVER_UNIQUE_ID, "9255143");
@@ -258,11 +212,11 @@ public class SuntechProtocolDecoderTest extends ProtocolTest {
}
- @Ignore
+ @Disabled
@Test
public void testDecodeCrash() throws Exception {
- var decoder = new SuntechProtocolDecoder(null);
+ var decoder = inject(new SuntechProtocolDecoder(null));
verifyAttribute(decoder, binary(
"4352523b303931303030303036333b313b313b303135303b16011c150f0ad82f6c0000000000ae037085fbff7700fd00faff6300f30000006800fb000d007100fa00f32f6c00000000005e044a80fcff6f000301e1ff5d00e900e1ff6400e600f4ff5b00ec000a306c00000000002104248306006c000501fcff5b00e00001006e000101eeff4e00e10022306c00000000005c041a7e00006a00010100005d00f800b5ff7cffdf0050009300fc003b44350d"),
@@ -270,4 +224,75 @@ public class SuntechProtocolDecoderTest extends ProtocolTest {
}
+ @Test
+ public void testDecodeTemperature() throws Exception {
+
+ var decoder = inject(new SuntechProtocolDecoder(null));
+
+ decoder.setHbm(true);
+ decoder.setIncludeAdc(true);
+
+ verifyAttribute(decoder, buffer(
+ "ST600STT;008594432;20;492;20200212;18:58:30;060bb0e1;334;20;36bb;45;+19.337897;-099.064489;000.398;000.00;12;1;5049883;13.61;100100;2;1198;013762;4.2;1;4.68"),
+ Position.PREFIX_ADC + 1, 4.68);
+
+ decoder.setIncludeTemp(true);
+
+ verifyAttribute(decoder, buffer(
+ "ST600STT;008350848;35;523;20191102;13:49:46;0bf14fdb;334;20;2f19;57;+20.466737;-100.825455;000.006;000.00;11;1;10274175;11.36;00000000;1;0300;018353;4.2;1;0.00;;;;00000000000000;0;28EE56B911160234:+13.7;:;:"),
+ Position.PREFIX_TEMP + 2, 13.7);
+
+ verifyPosition(decoder, buffer(
+ "ST300STT;205173382;07;564;20160322;23:23:18;232e19;+19.288278;-099.128750;000.122;000.00;9;1;478391;11.53;000100;1;9498;079324;4.3;1;0.00;0.00;0.00;00000000000000;0;2898E16006000058:-20.8;2861626006000039:+2.5;:"));
+
+ verifyPosition(decoder, buffer(
+ "ST300EVT;205173382;07;564;20160322;23:23:18;232e19;+19.288278;-099.128750;000.122;000.00;9;1;478391;11.53;000100;2;1;9498;079324;4.3;1;0.00;0.00;0.00;00000000000000;0;2898E16006000058:-20.8;2861626006000039:+2.5;:"));
+
+ verifyPosition(decoder, buffer(
+ "ST600STT;008349958;35;523;20181112;00:49:30;0bf10d4e;334;20;2f19;22;+20.552718;-100.824478;050.021;095.41;12;1;1303603;14.30;10000000;4;8911;001987;4.1;0;0.00;;;;00000000000000;0;2826C8A70800000C:+26.6;:;:"));
+
+ }
+
+ @Test
+ public void testDecodeRpm() throws Exception {
+
+ var decoder = inject(new SuntechProtocolDecoder(null));
+
+ decoder.setHbm(true);
+ decoder.setIncludeRpm(true);
+
+ verifyAttribute(decoder, buffer(
+ "ST300STT;907131077;04;706;20190227;23:59:34;cc719;-12.963490;-038.499587;000.067;000.00;7;1;57095;12.50;000000;1;0337;000207;0.0;1;0;012E717F010000;1"),
+ Position.KEY_RPM, 0);
+
+ }
+
+ @Test
+ public void testDecodeHours() throws Exception {
+
+ var decoder = inject(new SuntechProtocolDecoder(null));
+
+ decoder.setHbm(true);
+
+ verifyAttribute(decoder, buffer(
+ "ST300ALT;007239104;40;313;20190112;01:07:16;c99139;+04.703287;-074.148897;000.000;189.72;21;1;425512;12.61;100000;33;003188;4.1;1"),
+ Position.KEY_HOURS, 3188 * 60000L);
+
+ }
+
+ @Test
+ public void testDecodeDriver() throws Exception {
+
+ var decoder = inject(new SuntechProtocolDecoder(null));
+
+ verifyAttribute(decoder, buffer(
+ "ST300HTE;511050566;45;308;20200909;13:38:38;0;12.50;001354;0.0;1;0;1;1;0;-27.636632;-052.277933;-27.636675;-052.277947;000.000;002.296;0;00000000000000"),
+ Position.KEY_DRIVER_UNIQUE_ID, "00000000000000");
+
+ verifyAttribute(decoder, buffer(
+ "ST300HTE;100850001;04;248;20110101;00:13:52;167559;12.28;004005;0.0;1;0;3;3;0;-22.881018;-047.070831;-22.881018;-047.070831;000.000;000.000;0;0;3;0;0;0;01E04D44160000"),
+ Position.KEY_DRIVER_UNIQUE_ID, "01E04D44160000");
+
+ }
+
}
diff --git a/src/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java
index 29ec670aa..4fa209fb7 100755
--- a/src/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class SupermateProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class SupermateProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SupermateProtocolDecoder(null);
+ var decoder = inject(new SupermateProtocolDecoder(null));
verifyPosition(decoder, text(
"2:359672050130411:1:*,00000000,XT,A,10031b,140b28,80ad4c72,81ba2d2c,06ab,238c,020204010000,12,0,0000,0003e6"));
diff --git a/src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java
index 8a3a74753..694a178f4 100644
--- a/src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class SviasProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class SviasProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SviasProtocolDecoder(null);
+ var decoder = inject(new SviasProtocolDecoder(null));
verifyPosition(decoder, text(
"[7061,3041,57,20324277,710,40618,141342,-93155840,-371754060,0,20469,0,16,1,0,0,11323,100,9,,32,4695"));
diff --git a/src/test/java/org/traccar/protocol/SwiftechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SwiftechProtocolDecoderTest.java
index 10b033985..6b473b38c 100644
--- a/src/test/java/org/traccar/protocol/SwiftechProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SwiftechProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class SwiftechProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class SwiftechProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new SwiftechProtocolDecoder(null);
+ var decoder = inject(new SwiftechProtocolDecoder(null));
verifyPosition(decoder, text(
"@@861551041946971,,0,102040,1023.9670,N,07606.8160,E,2.26,151220,A,0127,1,1,03962,00000,#"));
diff --git a/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java
index ba981598d..7b9841d68 100644
--- a/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,13 @@ public class T55ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new T55ProtocolDecoder(null);
+ var decoder = inject(new T55ProtocolDecoder(null));
+
+ verifyAttributes(decoder, text(
+ "$GPTXT,NET,1003,A1,-53,232 01*77"));
+
+ verifyPosition(decoder, text(
+ "$PUBX,00,130209.00,3650.51159,N,01346.10602,E,785.947,D3,4.1,5.2,0.163,87.43,-0.054,7.0,0.88,1.21,0.88,24,01012,0*6D"));
verifyPosition(decoder, text(
"QZE,868994033976700,35,28062020,113553,22.13673,114.57263,0,22,A,0"));
@@ -121,7 +127,7 @@ public class T55ProtocolDecoderTest extends ProtocolTest {
// Maxon devices can send NMEA before identification
- var decoder = new T55ProtocolDecoder(null);
+ var decoder = inject(new T55ProtocolDecoder(null));
verifyNull(decoder, text(
"$GPRMC,012006,A,4828.10,N,1353.52,E,0.00,0.00,180915,020.3,E*42"));
diff --git a/src/test/java/org/traccar/protocol/T57FrameDecoderTest.java b/src/test/java/org/traccar/protocol/T57FrameDecoderTest.java
index dd5929b04..1e39298fa 100644
--- a/src/test/java/org/traccar/protocol/T57FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/T57FrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class T57FrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class T57FrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new T57FrameDecoder();
+ var decoder = inject(new T57FrameDecoder());
verifyFrame(
binary("2a5435372346312354353731313137303031233330313131372330303038343323323233342e31333033234e2330383832362e313731342345232b302e3234322c2b302e3130392c2d302e37383923302e30303023362e323030303023413223342e3223"),
diff --git a/src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java
index 376aab1da..e0fd2e800 100644
--- a/src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class T57ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class T57ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new T57ProtocolDecoder(null);
+ var decoder = inject(new T57ProtocolDecoder(null));
verifyPosition(decoder, text(
"*T57#F1#T571117001#301117#000843#2234.1303#N#08826.1714#E#+0.242,+0.109,-0.789#0.000#6.20000#A2#4.2#"));
diff --git a/src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java
new file mode 100644
index 000000000..ff5d5b0a0
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/T622IridiumProtocolDecoderTest.java
@@ -0,0 +1,21 @@
+package org.traccar.protocol;
+
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+
+public class T622IridiumProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new T622IridiumProtocolDecoder(null));
+
+ decoder.setFormat("01,02,03,04,05,08");
+
+ verifyPosition(decoder, binary(
+ "01003501001c68b2cb1733303034333430363735343836353000016e000064b5f497020013234c5ea0ff1c365d0600b1482c010000cf0004"),
+ position("2023-07-18 02:10:08.000", true, -6.26732, 106.77200));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java
index 1dd4e8619..3f62a834c 100644
--- a/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,13 @@ public class T800xProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new T800xProtocolDecoder(null);
+ var decoder = inject(new T800xProtocolDecoder(null));
+
+ verifyAttributes(decoder, binary(
+ "272704004901380864112055585747c612230321220006000036435fc8acc2ee600f420000000000000000909019003900001356a18000012c0000a8c00000001e20d4800000c00000"));
+
+ verifyAttributes(decoder, binary(
+ "2525110055000208677300508924902206262035310c540045004c00430045004c0004454447450847534d20313930300f323134303734323036373835323839143839333430373131373930303936383037363846"));
verifyAttributes(decoder, binary(
"27271000247bd00860112047066487210407034238000005d7d17365e625ff640a730148"));
diff --git a/src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java
index 1d17ee5d5..4741f5c92 100644
--- a/src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -9,7 +9,7 @@ public class T800xProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new T800xProtocolEncoder(null);
+ var encoder = inject(new T800xProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java
index 56af8830a..bc5901fb0 100644
--- a/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class TaipProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TaipProtocolDecoder(null);
+ var decoder = inject(new TaipProtocolDecoder(null));
verifyAttribute(decoder, text(
">RUS00,111220124402-3138067-06417623000012200FF,000000000000000000000000000,0000000111,15640422,00000,+25.5,00000,51;ID=CST3G0443;#IP1:089F;*34<"),
diff --git a/src/test/java/org/traccar/protocol/TechTltProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TechTltProtocolDecoderTest.java
index c5de8e62a..28a917096 100644
--- a/src/test/java/org/traccar/protocol/TechTltProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TechTltProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TechTltProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TechTltProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TechTltProtocolDecoder(null);
+ var decoder = inject(new TechTltProtocolDecoder(null));
verifyPosition(decoder, text(
"002422269*POS=Y,16:21:20,25/11/09,3809.8063N,01444.7438E,4.17,117.23,0.4,09,40076,56341\r\n"),
diff --git a/src/test/java/org/traccar/protocol/TechtoCruzFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TechtoCruzFrameDecoderTest.java
index dc4afb784..1e1f8d431 100644
--- a/src/test/java/org/traccar/protocol/TechtoCruzFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TechtoCruzFrameDecoderTest.java
@@ -1,16 +1,16 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class TechtoCruzFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TechtoCruzFrameDecoder();
+ var decoder = inject(new TechtoCruzFrameDecoder());
assertEquals(
buffer("$$A35,RESPO|G33|8612345678910|CRUZ,*E3"),
diff --git a/src/test/java/org/traccar/protocol/TechtoCruzProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TechtoCruzProtocolDecoderTest.java
index 4cef682b4..b512f9968 100644
--- a/src/test/java/org/traccar/protocol/TechtoCruzProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TechtoCruzProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TechtoCruzProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TechtoCruzProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TechtoCruzProtocolDecoder(null);
+ var decoder = inject(new TechtoCruzProtocolDecoder(null));
verifyPosition(decoder, text(
"$$A120,8612345678910,211005105836,A,FLEX,KCB 947C,000.0,0,-1.38047,S,36.93951,E,1648.4,243.140,21,28,12.1,3.7,0,1,0,0,0,*F6"));
diff --git a/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java
index f315e6432..fa6a490a4 100644
--- a/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TekFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TekFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TekFrameDecoder();
+ var decoder = inject(new TekFrameDecoder());
verifyFrame(
binary("020315048715E70861074028023219026200400A0340002C007F0009000000000000000000402842064028420641284206402844064128440640284406402844064028440641284406402844060010010C04052B000253000000000001060A0000000000000228330000FF0000FF360014B394"),
diff --git a/src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java
index a371ffe6b..9976b9bac 100644
--- a/src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TekProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TekProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TekProtocolDecoder(null);
+ var decoder = inject(new TekProtocolDecoder(null));
verifyPosition(decoder, binary(
"0501E304E00E76086107502100455111492C33332C3137303935342E302C353235352E393933344E2C30303833322E34333935572C322E312C3133342E382C322C302E30302C302E302C302E302C3234303931352C30362C3C45"));
diff --git a/src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java
index 8c3650f4e..8770e9451 100644
--- a/src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TelemaxProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TelemaxProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TelemaxProtocolDecoder(null);
+ var decoder = inject(new TelemaxProtocolDecoder(null));
verifyNull(decoder, text(
"%067374070128"));
diff --git a/src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java
index 125b61d48..ba3808534 100644
--- a/src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TelicFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TelicFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TelicFrameDecoder();
+ var decoder = inject(new TelicFrameDecoder());
verifyFrame(
binary("303032363230333339337c3232367c31307c303032303034303130"),
diff --git a/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java
index 03824d91b..44e63b8a6 100644
--- a/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TelicProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TelicProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TelicProtocolDecoder(null);
+ var decoder = inject(new TelicProtocolDecoder(null));
verifyNull(decoder, text(
"0026355565071347499|206|01|001002008"));
diff --git a/src/test/java/org/traccar/protocol/TeltonikaFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TeltonikaFrameDecoderTest.java
index 7787907b6..8d0cafcd9 100644
--- a/src/test/java/org/traccar/protocol/TeltonikaFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TeltonikaFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TeltonikaFrameDecoderTest extends ProtocolTest {
@@ -8,10 +8,10 @@ public class TeltonikaFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TeltonikaFrameDecoder();
+ var decoder = inject(new TeltonikaFrameDecoder());
verifyFrame(
- binary("000F313233343536373839303132333435"),
+ binary("ff"),
decoder.decode(null, null, binary("FF000F313233343536373839303132333435")));
verifyFrame(
diff --git a/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java
index c3c32369c..0b4f1d243 100644
--- a/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java
@@ -1,19 +1,36 @@
package org.traccar.protocol;
-import org.junit.Ignore;
-import org.junit.Test;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
+import org.traccar.model.Position;
public class TeltonikaProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TeltonikaProtocolDecoder(null, false);
+ var decoder = inject(new TeltonikaProtocolDecoder(null, false));
verifyNull(decoder, binary(
"000F313233343536373839303132333435"));
+ verifyAttribute(decoder, binary(
+ "00000000000000240d01060000001c642b3ad14754534c7c367c317c307c31323734393838347c317c0d0a010000ec11"),
+ Position.KEY_DRIVER_UNIQUE_ID, "12749884");
+
+ verifyPositions(decoder, binary(
+ "00000000000000a28e0100000183ac617e3001123eb99b1e142db4000000000000000000001d000900f000005000001503004500011e1801212d01242a012722012a18001100b5000000b600000018000000cd151000431c2d011f6981012047d701226981012347d901256981012647d8012869810129e6f304b0000304b1000304b2000304b30003000100f10000639d0002000b0000000214bf12fe000e0000000029d18c95000001000051b6"));
+
+ verifyPositions(decoder, binary(
+ "00000000000004258e0400000182a701b49301d5d90ab7ebe4aae101be003d12000000f7003d000e00f70100ef0000f00000500500150200c800004501000100001d00001400001600001700007157010701001d00b5000b00b60006004230400018000000cd223f00ce741700430f8900440000000d00010011ffe50012001f0013ffce000f03e800190bb8001a0bb8001b0bb8001c0bb800560bb800680bb8006a0bb8006c0bb8010e0000011100000114000001170000014f0000015000000151000001520000000a00f100011d2a00c700000000001000b9addc000c0000acb600040000000001320000000001330000000001340000000001350000000001c1000000000003000b000000d14675f36000ee0000000000000000000e0000000003fd509f0005014b0000014c0000014d0000014e0000018300222d3333373333382e0100000053a6fb624588040001ba86064f0eae51c0fdaf4d3de500000182a701b82001d5d90ab7ebe4aae101be003d12000000f0003c000d00ef0000f00100500500150200c800004501000100001d00001400001600001700007152010701001d00b5000900b60006004217e50018000000cd223f00ce741700430f5c00440000000d00010011fed60012fd1d0013f1f2000f03e800190bb8001a0bb8001b0bb8001c0bb800560bb800680bb8006a0bb8006c0bb8010e0000011100000114000001170000014f0000015000000151000001520000000a00f100011d2a00c700000000001000b9addc000c0000acb600040000000001320000000001330000000001340000000001350000000001c1000000000003000b000000d14675f36000ee0000000000000000000e0000000003fd509f0005014b0000014c0000014d0000014e0000018300222d3333373333352e353833332d303730373139362e323333332b3030302e3434362f00000182a701bc0801d5d90ab7ebe4aae101be003d12000000fc003d000e00ef0000f00100500500150200c800004501000100001d0000140000160000170000714d01070100fc01001d00b5000900b60006004217e50018000000cd223f00ce741700430f5c00440000000d00010011fed60012fd1d0013f1f2000f03e800190bb8001a0bb8001b0bb8001c0bb800560bb800680bb8006a0bb8006c0bb8010e0000011100000114000001170000014f0000015000000151000001520000000a00f100011d2a00c700000000001000b9addc000c0000acb600040000000001320000000001330000000001340000000001350000000001c1000000000003000b000000d14675f36000ee0000000000000000000e0000000003fd509f0005014b0000014c0000014d0000014e0000018300222d3333373333352e353833332d303730373139362e323333332b3030302e3434362f00000182a7018d8d01d5d8ffa6ebe4a0ca01be006111000000f70001000100f70500000000000000000400003a10"));
+
+ verifyPositions(decoder, binary(
+ "00000000000003831004000001735ace37f80000e3b9331c71e290006900e211005100fd072e1600010100160300470300f00100150400b20000c80000ef01009000004f00005101005201005300005538006e00006f00007a03007d00007f5600890000fd0200fe1f09004326b00044000000b5000b00b6000600427029001800540046015d00ce4ec10080000f0f00f10000515400cd007404ab00d80f5022a1005000000054005400000000005600015568005700000060005800000420006800001113006d303330300071fffd8c85008700000020008800000002008a000155f5008b0000b86000000001735ace3ca80000e3b08a1c71dd29006900e311005100fd072e1600010100160300470300f00100150400b20000c80000ef01009000004f00005101005201005300005537006e00006f00007a03007d00007f5600890000fd0200fe1d09004326ac0044000000b5000b00b600060042701f001800540046015d00ce4ec10080000f0f00f10000515400cd007404ab00d80f5022ce00500000005400540000000000560001556800570000006000580000041f006800001113006d303330300071fffd8c85008700000020008800000002008a000155f5008b0000b86000000001735ace3fc80000e3a7c01c71d7c2006900e311005100fd072e1600010100160300470300f00100150400b20000c80000ef01009000004f00005101005201005300005537006e00006f00007a03007d00007f5600890000fd0200fe2309004326ac0044000000b5000b00b6000600427015001800540046015e00ce4ec10080000f0f00f10000515400cd007404ab00d80f5022e700500000005400540000000000560001556800570000006000580000041f006800001113006d303330300071fffd8c85008700000020008800000002008a000155f5008b0000b86000000001735ace3ffa0000e3a7c01c71d7c2006900e311005100fd072e1600010100160300470300f00100150400b20000c80000ef01009000004f00005101005201005300005537006e00006f00007a03007d00007f5600890000fd0300fe2309004326ac0044000000b5000b00b6000600427015001800540046015e00ce4ec10080000f0f00f10000515400cd007404ab00d80f5022e700500000005400540000000000560001556800570000006000580000041f006800001113006d303330300071fffd8c85008700000020008800000002008a000155f5008b0000b86000040000eb85"));
+
+ verifyPositions(decoder, binary(
+ "00000000000000e708030000018293d62060000de1f6a62159767e00000000000000000b074504f00050041500c801ef004f630342320043000344000001f100006019000000018291b0c790000de1f6a62159767e006e0144070000ef12074503f00050051505c800ef004f0207b5000eb6000b423324180000ce00dc43001144000004c700000007f100006019cd0003c7776300ea4e2e000000018291aff0b8000de1f91f21597405006f00f61300080012074503f00150051504c800ef014f0207b50009b600054236c1180008ce00dc43003f44000004c700000003f100006019cd0003c7776300ea4e2700030000a48d"));
+
verifyPositions(decoder, binary(
"00000000000000da08030000017fcedf499600280431be0eded45d0038012d100000fa100901000200b300b4004501500415034702fa00054232a1180000cd3b2fce281d43001f02c700000006f10000a029000000017fcedea99600280432070eded3dd00380046130009000f0801010200b300b400450150051502470205423276180009cd3b2fce281d43001f02c700000027f10000a0290000000179d50853180027f65d3f0ed67212001500f1110061000f0801010200b300b4004501500515034702054234f4180061cd53d1ce28c043003e02c700000147f1000000290003000052cb"));
@@ -113,6 +130,9 @@ public class TeltonikaProtocolDecoderTest extends ProtocolTest {
verifyPositions(decoder, binary(
"000000000000004a08010000015ebc1da508002411926621f15246010b00b913005e000f06ef01f00150011505c800450108b5000bb6000642381b18005ecd0318ce19cd430f5844000001f1000061a900010000c8e1"));
+ verifyNull(decoder, binary(
+ "ff"));
+
decoder.setExtended(true);
verifyPositions(decoder, false, binary(
@@ -127,7 +147,7 @@ public class TeltonikaProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecodePhoto() throws Exception {
- var decoder = new TeltonikaProtocolDecoder(null, false);
+ var decoder = inject(new TeltonikaProtocolDecoder(null, false));
verifyNull(decoder, binary(
"000F313233343536373839303132333435"));
@@ -143,11 +163,11 @@ public class TeltonikaProtocolDecoderTest extends ProtocolTest {
}
- @Ignore
+ @Disabled
@Test
public void testDecodeConnectionless() throws Exception {
- var decoder = new TeltonikaProtocolDecoder(null, true);
+ var decoder = inject(new TeltonikaProtocolDecoder(null, true));
verifyPositions(decoder, false, binary(
"0049cafe0122000f33353734353430373237313339373508010000015d3766f6a800003eef961ec6215e0063006d09003100070401000200f001c8000242381c18003201c7000000e10001"));
diff --git a/src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java
index 008a2b9dd..04e8afe0b 100644
--- a/src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -9,7 +9,7 @@ public class TeltonikaProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new TeltonikaProtocolEncoder(null);
+ var encoder = inject(new TeltonikaProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/TeraTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TeraTrackProtocolDecoderTest.java
index 6f96f73ad..674db0ad5 100644
--- a/src/test/java/org/traccar/protocol/TeraTrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TeraTrackProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TeraTrackProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TeraTrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TeraTrackProtocolDecoder(null);
+ var decoder = inject(new TeraTrackProtocolDecoder(null));
verifyAttributes(decoder, text(
"{\"MDeviceID\":\"022043756090\",\"DiviceType\":\"1\",\"DataType\":\"1\",\"DataLength\":\"69\",\"DateTime\":\"2022-03-09 10:56:01\",\"Latitude\":\"-6.846451\",\"Longitude\":\"39.316324\",\"LongitudeState\":\"1\",\"LatitudeState\":\"0\",\"Speed\":\"90\",\"Mileage\":\"0\",\"FenceAlarm\":\"0\",\"AreaAlarmID\":\"0\",\"LockCutOff\":\"0\",\"SealTampered\":\"0\",\"MessageAck\":\"1\",\"LockRope\":\"1\",\"LockStatus\":\"1\",\"LockOpen\":\"0\",\"PasswordError\":\"0\",\"CardNo\":\"60000644\",\"IllegalCard\":\"0\",\"LowPower\":\"0\",\"UnCoverBack\":\"0\",\"CoverStatus\":\"1\",\"LockStuck\":\"0\",\"Power\":\"79\",\"GSM\":\"16\",\"IMEI\":\"860922043756090\",\"Index\":\"20\",\"Slave\":[]}"));
diff --git a/src/test/java/org/traccar/protocol/ThinkPowerProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ThinkPowerProtocolDecoderTest.java
index ff808e667..0271bf3a2 100644
--- a/src/test/java/org/traccar/protocol/ThinkPowerProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ThinkPowerProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class ThinkPowerProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class ThinkPowerProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new ThinkPowerProtocolDecoder(null);
+ var decoder = inject(new ThinkPowerProtocolDecoder(null));
verifyNull(decoder, binary(
"0103002C01020F38363737333030353038323030343606544C3930344111522D312E302E31372E32303231303431300011C3"));
diff --git a/src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java
index 39e7ed473..73e40ce55 100644
--- a/src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class ThinkRaceProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class ThinkRaceProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new ThinkRaceProtocolDecoder(null);
+ var decoder = inject(new ThinkRaceProtocolDecoder(null));
verifyNull(decoder, binary(
"48415349483031343730303134382C8000100134363030303134363139363239343806FF"));
diff --git a/src/test/java/org/traccar/protocol/ThurayaProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ThurayaProtocolDecoderTest.java
new file mode 100644
index 000000000..b9bc1dbc2
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/ThurayaProtocolDecoderTest.java
@@ -0,0 +1,24 @@
+package org.traccar.protocol;
+
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+
+public class ThurayaProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new ThurayaProtocolDecoder(null));
+
+ verifyPositions(decoder, binary(
+ "235400437101072bca3c0201348b9a00014c9f085493fc02200c5411470000000042323a300001348b9a00014d03085493ea02200c5010000000000042323a3000f2c1"));
+
+ verifyPosition(decoder, binary(
+ "2354002b5101072bca3c01348b9a00013fba000000000000000010000000000042323a3000174f4e00f9de"));
+
+ verifyNull(decoder, binary(
+ "235400d88115071e37d691030133342e3233362e3133302e3637000000001e56313030320030000700080102030405060708020101010101020201030103030302020000007800000078000004b000001c20050a64000015b3800015b374657374696e67003132333435360002010f28393031303539383938303134373738000043383a592c43373a592c43333a592c43323a592c43313a592c42353a592c42343a592c42323a592c42313a592c41323a592c41313a590045313a592c45373a590065746973616c61742e61650047455400322e3130d6de"));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java
index 2185fda29..2c495d09d 100644
--- a/src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Tk102ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Tk102ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Tk102ProtocolDecoder(null);
+ var decoder = inject(new Tk102ProtocolDecoder(null));
verifyNull(decoder, buffer(
"[\u00800000000000\u000821315452]"));
diff --git a/src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java
index 57df2ac5b..a3cfa24cf 100644
--- a/src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java
@@ -1,7 +1,7 @@
package org.traccar.protocol;
import io.netty.buffer.ByteBuf;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Tk103FrameDecoderTest extends ProtocolTest {
@@ -9,7 +9,7 @@ public class Tk103FrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Tk103FrameDecoder();
+ var decoder = inject(new Tk103FrameDecoder());
verifyFrame(
binary("283836343735353535353535353535352C445733422C3133313131372C412C353536322E30323837304E2C30313334382E3038313934452C312E3539372C3232333730372C3239312E36352C2D302E31302C3429"),
diff --git a/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java
index 321d0cb50..a3b3fa86b 100644
--- a/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,20 @@ public class Tk103ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Tk103ProtocolDecoder(null);
+ var decoder = inject(new Tk103ProtocolDecoder(null));
+
+ verifyAttributes(decoder, text(
+ "(007030201454BS5190:02150000753001DC,91:0EE8060EDC0A01DC,92:42014201DC0A01DC,93:00010127000037C8,94:0E01000002000000,95:020EE10EE20EE800030EE40EE00EE700040EDD0EE40EE400050EDC0EDF0EE400,96:0142000000000000,97:0000000000000000,98:0000000000000000)"));
+
+ verifyAttribute(decoder, text(
+ "(352602014867BS500064FF0EF10FF10FF00FF20FF30FF20FF20FF40FF20FF40FF40FF20FF30FF20F0000000000000000000000000000000000000000000000001663000000010004000000000000000002444444420000000000A00FA000000000000000200000000315E2000000)"),
+ "batteryTemp2", 26);
+
+ verifyAttributes(decoder, text(
+ "(027046434858BZ00,{460,0,20949,58711}\n{460,0,20494,54003}\n{460,0,20951,19569}\n,01000000)"));
+
+ verifyAttributes(decoder, text(
+ "(027045009305BP05355227045009305,{413,2,30073,16724}\n{413,2,30073,16730}\n{413,2,30073,49860}\n,01000000)"));
verifyPosition(decoder, text(
"(868822040452227,DW3B,150421,A,4154.51607N,45.78950E,0.050,103142,0.000,595.200,7,0)"));
diff --git a/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java
index c34674128..57ebbaec1 100644
--- a/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class Tk103ProtocolEncoderTest extends ProtocolTest {
@Test
- public void testEncodeOutputControl() {
+ public void testEncodeOutputControl() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null);
+ var encoder = inject(new Tk103ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -23,9 +23,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeEngineStop() {
+ public void testEncodeEngineStop() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null);
+ var encoder = inject(new Tk103ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -36,9 +36,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodePositionSingle() {
+ public void testEncodePositionSingle() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null);
+ var encoder = inject(new Tk103ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -49,9 +49,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodePositionPeriodic() {
+ public void testEncodePositionPeriodic() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null);
+ var encoder = inject(new Tk103ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -63,9 +63,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodePositionStop() {
+ public void testEncodePositionStop() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null);
+ var encoder = inject(new Tk103ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -76,9 +76,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeGetVersion() {
+ public void testEncodeGetVersion() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null);
+ var encoder = inject(new Tk103ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -89,9 +89,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeRebootDevice() {
+ public void testEncodeRebootDevice() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null);
+ var encoder = inject(new Tk103ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -102,9 +102,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeSetOdometer() {
+ public void testEncodeSetOdometer() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null);
+ var encoder = inject(new Tk103ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -115,9 +115,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodePositionSingleAlternative() {
+ public void testEncodePositionSingleAlternative() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null, true);
+ var encoder = inject(new Tk103ProtocolEncoder(null, true));
Command command = new Command();
command.setDeviceId(1);
@@ -128,9 +128,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodePositionPeriodicAlternative() {
+ public void testEncodePositionPeriodicAlternative() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null, true);
+ var encoder = inject(new Tk103ProtocolEncoder(null, true));
Command command = new Command();
command.setDeviceId(1);
@@ -141,9 +141,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodePositionStopAlternative() {
+ public void testEncodePositionStopAlternative() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null, true);
+ var encoder = inject(new Tk103ProtocolEncoder(null, true));
Command command = new Command();
command.setDeviceId(1);
@@ -154,9 +154,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeGetVersionAlternative() {
+ public void testEncodeGetVersionAlternative() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null, true);
+ var encoder = inject(new Tk103ProtocolEncoder(null, true));
Command command = new Command();
command.setDeviceId(1);
@@ -167,9 +167,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeRebootDeviceAlternative() {
+ public void testEncodeRebootDeviceAlternative() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null, true);
+ var encoder = inject(new Tk103ProtocolEncoder(null, true));
Command command = new Command();
command.setDeviceId(1);
@@ -180,9 +180,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeIdentificationAlternative() {
+ public void testEncodeIdentificationAlternative() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null, true);
+ var encoder = inject(new Tk103ProtocolEncoder(null, true));
Command command = new Command();
command.setDeviceId(1);
@@ -193,9 +193,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeSosOnAlternative() {
+ public void testEncodeSosOnAlternative() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null, true);
+ var encoder = inject(new Tk103ProtocolEncoder(null, true));
Command command = new Command();
command.setDeviceId(1);
@@ -207,9 +207,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeSosOffAlternative() {
+ public void testEncodeSosOffAlternative() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null, true);
+ var encoder = inject(new Tk103ProtocolEncoder(null, true));
Command command = new Command();
command.setDeviceId(1);
@@ -221,9 +221,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeCustom() {
+ public void testEncodeCustom() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null);
+ var encoder = inject(new Tk103ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -235,9 +235,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeCustomAlternative() {
+ public void testEncodeCustomAlternative() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null, true);
+ var encoder = inject(new Tk103ProtocolEncoder(null, true));
Command command = new Command();
command.setDeviceId(1);
@@ -249,9 +249,9 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeSetConnectionAlternative() {
+ public void testEncodeSetConnectionAlternative() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null, true);
+ var encoder = inject(new Tk103ProtocolEncoder(null, true));
Command command = new Command();
command.setDeviceId(1);
@@ -264,14 +264,14 @@ public class Tk103ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeSosNumberAlternative() {
+ public void testEncodeSosNumberAlternative() throws Exception {
- var encoder = new Tk103ProtocolEncoder(null, true);
+ var encoder = inject(new Tk103ProtocolEncoder(null, true));
Command command = new Command();
command.setDeviceId(1);
command.setType(Command.TYPE_SOS_NUMBER);
- command.set(Command.KEY_INDEX, "0");
+ command.set(Command.KEY_INDEX, 0);
command.set(Command.KEY_PHONE, "+55555555555");
command.set(Command.KEY_DEVICE_PASSWORD, "232323");
diff --git a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java
index b747fa960..46dc031a3 100644
--- a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class Tlt2hProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Tlt2hProtocolDecoder(null);
+ var decoder = inject(new Tlt2hProtocolDecoder(null));
verifyNull(decoder, text(
"#860517049471362#MT700#0000#AUTO#1\r\n",
@@ -81,6 +81,13 @@ public class Tlt2hProtocolDecoderTest extends ProtocolTest {
"#357671031289215#V600#0000#AUTOLOW#1\r\n",
"#00735e1c$GPRMC,115647.000,A,5553.6524,N,02632.3128,E,0.00,0.0,130614,0.0,W,A*28"));
+ verifyPositions(decoder, false, text(
+ "#860186058100000#MT700#0000#AUTO#1\r\n",
+ "#39#262,03,8CE6,A672$WIFI,154928.00,A,-74,3CA62F52615B,-82,A0E4CB83852D,,,050123*28\r\n##\r\n"));
+
+ verifyPositions(decoder, false, text(
+ "#860186058100000#MT700#0000#AUTO#1\r\n",
+ "#39#262,03,8CE6,A672$GPRMC,115419.00,V,,,,,,,050123,,,A*7D\r\n##\r\n"));
}
}
diff --git a/src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java
index 54d66dac9..547014752 100644
--- a/src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TlvProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TlvProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TlvProtocolDecoder(null);
+ var decoder = inject(new TlvProtocolDecoder(null));
verifyNull(decoder, binary(
"30430f383630323437303330303934333931ff10393233323132323030303834353433340f533636385f415f56312e30315f454eff1130303a30433a45373a30303a30303a30300132"));
diff --git a/src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java
index 886470745..fe9ac26f1 100644
--- a/src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TmgFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TmgFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TmgFrameDecoder();
+ var decoder = inject(new TmgFrameDecoder());
verifyNull(
decoder.decode(null, null, binary("2424242424")));
diff --git a/src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java
index 722df5306..12402e068 100644
--- a/src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TmgProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TmgProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TmgProtocolDecoder(null);
+ var decoder = inject(new TmgProtocolDecoder(null));
verifyPosition(decoder, text(
"$loc,869309013800417,08032014,094459,1,2826.1956,N,07659.7690,E,0.0,2.5,4441,31,6,95,1,LLLL,NNTN,HH,0.15,0.26,HR38AU1389,0,SW0.1a"));
diff --git a/src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java
index dbc7210e0..67b04446e 100644
--- a/src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TopflytechProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TopflytechProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TopflytechProtocolDecoder(null);
+ var decoder = inject(new TopflytechProtocolDecoder(null));
verifyPosition(decoder, text(
"(880316890094910BP00XG00b600000000L00074b54S00000000R0C0F0014000100f0130531152205A0706.1395S11024.0965E000.0251.25"));
diff --git a/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java
index e8da93006..b55e12e9d 100644
--- a/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class TopinProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TopinProtocolDecoder(null);
+ var decoder = inject(new TopinProtocolDecoder(null));
verifyNull(decoder, binary(
"787801080D0A"));
@@ -17,6 +17,9 @@ public class TopinProtocolDecoderTest extends ProtocolTest {
verifyNull(decoder, binary(
"78780d0103593390754169634d0d0a"));
+ verifyNotNull(decoder, binary(
+ "787803181604130318491475905bd30e25001e10bbf7635d14759006e626560401cc00000028660090df425f000028660090df576c00002866009487566700002866009ca15667000d0a"));
+
verifyAttribute(decoder, binary(
"7878006921120412565802010601071e4a9764071e4a9864010d0a"),
Position.KEY_ALARM, Position.ALARM_VIBRATION);
diff --git a/src/test/java/org/traccar/protocol/TopinProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/TopinProtocolEncoderTest.java
index d3ff13941..b6ba9b0eb 100644
--- a/src/test/java/org/traccar/protocol/TopinProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/TopinProtocolEncoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -9,7 +9,7 @@ public class TopinProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new TopinProtocolEncoder(null);
+ var encoder = inject(new TopinProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java
index 95949c51b..5eff60e51 100644
--- a/src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TotemFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TotemFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TotemFrameDecoder();
+ var decoder = inject(new TotemFrameDecoder());
verifyFrame(
binary("24243030323542423836323031303033373239343836313345"),
diff --git a/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java
index e16774782..949e69275 100644
--- a/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java
@@ -1,14 +1,22 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
+import org.traccar.model.Position;
public class TotemProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TotemProtocolDecoder(null);
+ var decoder = inject(new TotemProtocolDecoder(null));
+
+ verifyAttribute(decoder, text(
+ "$$0494E2123456789012345|150425223945,113.925525,22.55814,1122334455|38"),
+ Position.KEY_DRIVER_UNIQUE_ID, "1122334455");
+
+ verifyPosition(decoder, text(
+ "$$0111AA353081090067318|0804400022070722520240400005B364ED5003107300001.700000002245.3919N10231.6952W000001860E"));
verifyPosition(decoder, text(
"$$0112E5864606045334223|201112223514,-68.923106,-22.455926,$Cloud,1738,621,730,12100,0,0,255,0,40,40,0,0,255,|13"));
diff --git a/src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java
index a4fca2d9e..795f75842 100644
--- a/src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class TotemProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new TotemProtocolEncoder(null);
+ var encoder = inject(new TotemProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(2);
@@ -25,7 +25,7 @@ public class TotemProtocolEncoderTest extends ProtocolTest {
@Test
public void testSmsEncode() throws Exception {
- var encoder = new TotemProtocolSmsEncoder(null);
+ var encoder = inject(new TotemProtocolSmsEncoder(null));
Command command = new Command();
command.setDeviceId(2);
diff --git a/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java
index def280b04..1323691c6 100644
--- a/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Tr20ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,10 @@ public class Tr20ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Tr20ProtocolDecoder(null);
+ var decoder = inject(new Tr20ProtocolDecoder(null));
+
+ verifyPosition(decoder, text(
+ "%%m13,L,221221103115,N1237.2271W00801.9500,000,000,B13.1:F0.0,04020000,253,CFG:133.00|"));
verifyPosition(decoder, text(
"%%TR20GRANT,L,210602170135,N0951.1733W08356.7672,000,000,C80:F0,00020008,108,CFG:6980.00|"));
diff --git a/src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java
index d3d35b356..636f2101a 100644
--- a/src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Tr900ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Tr900ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Tr900ProtocolDecoder(null);
+ var decoder = inject(new Tr900ProtocolDecoder(null));
verifyPosition(decoder, text(
">00001001,4,1,150626,131252,W05830.2978,S3137.2783,,00,348,18,00,003-000,0,3,11111011*3b!"),
diff --git a/src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java
index caac520e1..514ef2647 100644
--- a/src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TrackboxProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TrackboxProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TrackboxProtocolDecoder(null);
+ var decoder = inject(new TrackboxProtocolDecoder(null));
verifyNull(decoder, text(
"a=connect&v=11&i=111111111111111"));
diff --git a/src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java
index ef99527d7..55ccd2f0b 100644
--- a/src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TrakMateProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TrakMateProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TrakMateProtocolDecoder(null);
+ var decoder = inject(new TrakMateProtocolDecoder(null));
verifyPosition(decoder, text(
"^TMSTP|352984083995323|116|13.07809|77.55979|131508|131118|0.0|146.51|7|0|71 -2 248|0|13.1|0.0|10.5|1|0|0|0|#"));
diff --git a/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java
index 80e6a6e81..8c88f0ebb 100644
--- a/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TramigoFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,11 @@ public class TramigoFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TramigoFrameDecoder();
+ var decoder = inject(new TramigoFrameDecoder());
+
+ verifyFrame(
+ binary("0480001df35b1b69101a023ef34f0090436d38003200380e0000850081c0e4ff6d542f00000015000000050000000000007600a20100008f436d3800014400000000000000000021000a0006005a574a6169726f7320486972692043656e747265205072696d617279205363686f6f6c536f7574686572746f6e486172617265"),
+ decoder.decode(null, null, binary("0480001df35b1b69101a023ef34f0090436d38003200380e0000850081c0e4ff6d542f00000015000000050000000000007600a20100008f436d3800014400000000000000000021000a0006005a574a6169726f7320486972692043656e747265205072696d617279205363686f6f6c536f7574686572746f6e486172617265")));
verifyFrame(
binary("8000ed2bb0009c000101bee000050b09633d925b5472616d69676f3a205472697020737461727465642c2053686f636b2053656e736f722c206174204b696e6720437265656b20526f61642d46726565746f776e205374726565742c20506f727420486172636f7572742c205269766572732c204e472c20342e37363336312c20372e30313836382c2030373a31383a333620536570203320454f46"),
diff --git a/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java
index 8b556b356..dc0ca2b73 100644
--- a/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TramigoProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,13 @@ public class TramigoProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TramigoProtocolDecoder(null);
+ var decoder = inject(new TramigoProtocolDecoder(null));
+
+ verifyNull(decoder, binary(
+ "04d000a9e45c1b69101a023ef34f00549eec63047795ec63000000004eff5c0062c2e4ffbf612f00ce9aec63000000007700960180c0e4ff5f542f004c1200007b004a023d0200000001430000000000000000001f000b0006005a57436f63612d436f6c6120426f74746c696e6720506c616e74204861726172654772616e69746573696465486172617265014400000000000000000021000a0006005a574a6169726f7320486972692043656e747265205072696d617279205363686f6f6c536f7574686572746f6e486172617265"));
+
+ verifyPosition(decoder, binary(
+ "0480001df35b1b69101a023ef34f0090436d38003200380e0000850081c0e4ff6d542f00000015000000050000000000007600a20100008f436d3800014400000000000000000021000a0006005a574a6169726f7320486972692043656e747265205072696d617279205363686f6f6c536f7574686572746f6e486172617265"));
verifyAttributes(decoder, binary(
"8000c426b000a6000101c557037598050d5c8a595472616d69676f3a204d6f76696e672c20302e3132206b6d2045206f66204c617275742054696e2049736c616d6963205072696d617279205363686f6f6c2c2054616970696e672c20506572616b2c204d592c20342e38333134392c203130302e37333038352c204e572077697468207370656564203130206b6d2f682c2030303a34393a30382041756720392020454f46"));
diff --git a/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java
new file mode 100644
index 000000000..27f53b574
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/TranSyncProtocolDecoderTest.java
@@ -0,0 +1,21 @@
+package org.traccar.protocol;
+
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+
+public class TranSyncProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new TranSyncProtocolDecoder(null));
+
+ verifyPosition(decoder, binary(
+ "3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000100000050252ee060200822323"));
+
+ verifyAttributes(decoder, binary(
+ "3a3a2b583f086065705154043900801017050b11190f01623ef40887dff00000c25e9ff707000007152a2d0000000105004794916902050000000000050252ee060200822323"));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java
index 33d4e0124..31cb5b36d 100644
--- a/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TrvProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TrvProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TrvProtocolDecoder(null);
+ var decoder = inject(new TrvProtocolDecoder(null));
verifyNull(decoder, text(
"TRVAP00352121088015548"));
diff --git a/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java
index 5d0e86a3f..e471671f8 100644
--- a/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Tt8850ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Tt8850ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Tt8850ProtocolDecoder(null);
+ var decoder = inject(new Tt8850ProtocolDecoder(null));
verifyPosition(decoder, text(
"\u0000\u0004,007F,0,GTFRI,020102,867844000667538,4142726856,0,0,1,3,1.6,0,997.3,-66.830786,10.483394,20171212171418,0734,0004,041A,4220,69,20171212171657,FF61"));
diff --git a/src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java
index 1cab0f8b1..d42a249e8 100644
--- a/src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class TytanProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class TytanProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TytanProtocolDecoder(null);
+ var decoder = inject(new TytanProtocolDecoder(null));
verifyPositions(decoder, binary(
"B500192000001405125652CA9B1A325FC98D11A9990018020118FC0D"));
diff --git a/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java
index fba8f7db4..d90e5e07e 100644
--- a/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java
@@ -1,14 +1,22 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
+import org.traccar.model.Position;
public class TzoneProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TzoneProtocolDecoder(null);
+ var decoder = inject(new TzoneProtocolDecoder(null));
+
+ verifyAttribute(decoder, binary(
+ "545a00d424240153011300000863835029944118170316023b180016040485c73d2479187e170316023b1800000000060c000000000d1cc0406303019904aa00000000008a012520205e544f4e474c4f4d245049544f4f4e244d522e5e5e3f3b363030373634333132303130303134323234323d3139303631393538313032363d3f2b2020202020202020202020202032322020202020202020202020203120202020202020202020202030303234363238202031303730302020202020202020202020202020202020202020203f00030080000006e80e0d0a"),
+ Position.KEY_CARD, "% ^TONGLOM$PITOON$MR.^^?;6007643120100142242=190619581026=?+ 22 1 0024628 10700 ?");
+
+ verifyAttributes(decoder, binary(
+ "545a003724240407020200000180322000001610160b151019100000000c010a07320101088600007dca000baa102837016a0114025500000169e80d0a"));
verifyAttributes(decoder, binary(
"545a004d24240407010d0000018032100000031515090c052c2100000022030a033400201347000056860a03340020134700002feb0a03340020134700007d96000baa10211f01810127022d000001ebe00d0a"));
diff --git a/src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java b/src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java
index 77afbb50f..9b10328f6 100644
--- a/src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class UlbotechFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class UlbotechFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new UlbotechFrameDecoder();
+ var decoder = inject(new UlbotechFrameDecoder());
verifyFrame(
binary("f8010103515810532780699f7e2e3f010e015ee4c906bde45c00000000008b0304004000000404002c776005060373193622110b00240b00fee8ffff807dffff606d0b00fee9af000000af0000000b00feee7d78807dffffffff100101cc2af8"),
diff --git a/src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java
index b7c6d2d45..5d2692a8a 100644
--- a/src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class UlbotechProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class UlbotechProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new UlbotechProtocolDecoder(null);
+ var decoder = inject(new UlbotechProtocolDecoder(null));
verifyPosition(decoder, binary(
"f801010353323083177450a703f6f0010efe55a31a0923d01400050070007003040a42000004040070cca00506039b1876220f060800000000000000000725310553410c0c9e310d05310f4641100440311119411f00476101810f8000310487411f00480804203a14c009033320159310f8"));
diff --git a/src/test/java/org/traccar/protocol/UlbotechProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/UlbotechProtocolEncoderTest.java
index 288f8dc70..0ee1516ba 100644
--- a/src/test/java/org/traccar/protocol/UlbotechProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/UlbotechProtocolEncoderTest.java
@@ -1,15 +1,15 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
public class UlbotechProtocolEncoderTest extends ProtocolTest {
@Test
- public void testEncode() {
+ public void testEncode() throws Exception {
- var encoder = new UlbotechProtocolEncoder(null);
+ var encoder = inject(new UlbotechProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java
index 8c12f48f7..c99166374 100644
--- a/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class UproProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new UproProtocolDecoder(null);
+ var decoder = inject(new UproProtocolDecoder(null));
verifyPosition(decoder, buffer(
"*HQ201999999,BA&A1656512233362911356523660000230618&B0100060010&C00000<6<&F0000&R2405&V0109&W0000003E&K00100&T65&I54600027A00FCB6227A00FCA5727A00E955327A00E8B5327A00F9748&Y54600027A000000FCB6227A000000FCA5727A000000E955327A000000E8B5327A000000F9748&b00A7E81007607#"));
@@ -53,7 +53,7 @@ public class UproProtocolDecoderTest extends ProtocolTest {
verifyPosition(decoder, buffer(
"*MG201693502000034964,AB&A0800253335360507036975710000091116&P0730000032d2a94d&B0000000000&N13&Z12&U_P\0\0\0\u0004\0\0\0\0\0\0\0\0\0\0"),
- position("2016-11-09 08:00:25.000", true, -33.58934, -70.61626));
+ position("2016-11-09 08:00:25.000", false, -33.58934, -70.61626));
verifyNull(decoder, buffer(
"*MG20113800138000,AH"));
@@ -69,7 +69,7 @@ public class UproProtocolDecoderTest extends ProtocolTest {
verifyPosition(decoder, buffer(
"*AI200905300036,AH&A0317264913209801844913060000251115&B0500000000&C0;4?72:9&F0000"),
- position("2015-11-25 03:17:26.000", false, 49.22016, 18.74855));
+ position("2015-11-25 03:17:26.000", true, 49.22016, 18.74855));
verifyPosition(decoder, buffer(
"*AI2000905300036,AS&A1647304913209801844913060000251115&B0400000000&C0;4?72:9&F0000"));
diff --git a/src/test/java/org/traccar/protocol/UuxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/UuxProtocolDecoderTest.java
index 753063d26..492f241e5 100644
--- a/src/test/java/org/traccar/protocol/UuxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/UuxProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class UuxProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class UuxProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new UuxProtocolDecoder(null);
+ var decoder = inject(new UuxProtocolDecoder(null));
verifyNull(decoder, binary(
"81910b01ff"));
diff --git a/src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java
index 59b6dbea9..d8e3f1f53 100644
--- a/src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class V680ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class V680ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new V680ProtocolDecoder(null);
+ var decoder = inject(new V680ProtocolDecoder(null));
verifyPosition(decoder, text(
"#867967020910610#01234567890#1#0000#AUT#1#0500000000120000#114.036291,E,22.665795,N,111.00,000.00#111116#193333##"),
diff --git a/src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java
index b079346c9..ff43a94ab 100644
--- a/src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class VisiontekProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class VisiontekProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new VisiontekProtocolDecoder(null);
+ var decoder = inject(new VisiontekProtocolDecoder(null));
verifyPosition(decoder, text(
"$1,117,28,01,16,15,05,48,1725.0518N,07824.5298E,0620,11,0,185,2062,0,0,0,1,1,1,1,24,00.0000,00.3740,00.0000,VAJRA V1.00,A"));
diff --git a/src/test/java/org/traccar/protocol/VltProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/VltProtocolDecoderTest.java
new file mode 100644
index 000000000..e0e88b324
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/VltProtocolDecoderTest.java
@@ -0,0 +1,22 @@
+package org.traccar.protocol;
+
+import io.netty.handler.codec.http.HttpMethod;
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+
+public class VltProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new VltProtocolDecoder(null));
+
+ verifyPosition(decoder, request(HttpMethod.POST, "/",
+ buffer("vltdata=NRM12345678901234501L1060418102230023.125503N080.068033E4041231234123456789070.48120.5025273011M")));
+
+ verifyPositions(decoder, request(HttpMethod.POST, "/",
+ buffer("vltdata=BTH86123004167306301301L1240323181909009.226018N076.794980E404x19601d000037596000.00198.7013011401S02H1240323181807009.226018N076.794980E404x72090a000000000000.00198.7013011101S02H1240323181707009.226018N076.794980E404x72090a000014598000.00198.7013011101S02H1240323181605009.226018N076.794982E404x72090a000014596000.00198.7013011101S02H1240323181504009.226018N076.794982E404x72090a000014596000.00198.7013010901S02H1240323181402009.226018N076.794980E404x72090a000014596001.67198.0013021301S02H1240323181306009.226010N076.794980E404x72090a000014596000.00174.0013021401S02H1240323181155009.226010N076.794980E404x72090a088511008000.00174.0013011201S02H1240323181057009.226010N076.794980E404x72090a000014596000.00174.0013011201S02H1240323180958009.226010N076.794980E404x72090a000014596000.00174.0013021401S02H1240323180858009.226010N076.794980E404x72090a000014596001.48174.0013021201S02H1240323180755009.226005N076.794982E404x72090a000014598000.00164.4013011301S02H1240323180652009.226005N076.794982E404x72090a000014598000.00164.4013021101S")));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/VnetProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/VnetProtocolDecoderTest.java
index d43176a45..ead1624d8 100644
--- a/src/test/java/org/traccar/protocol/VnetProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/VnetProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class VnetProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class VnetProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new VnetProtocolDecoder(null);
+ var decoder = inject(new VnetProtocolDecoder(null));
verifyNull(decoder, binary(
"24240000140029111909062986818303379282604c452e322e30302ea32b020f0000d3552323"));
diff --git a/src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java
index 91cc3d317..a869e7dc1 100644
--- a/src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Vt200FrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Vt200FrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Vt200FrameDecoder();
+ var decoder = inject(new Vt200FrameDecoder());
verifyFrame(
binary("28631037309456208400340102dc0906171616454415760201144494473f920a0c0000030500200100417c1f383a9d1090510000006a00007000000e00180ee129"),
diff --git a/src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java
index 791751c27..c4533aa11 100644
--- a/src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -9,7 +9,7 @@ public class Vt200ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Vt200ProtocolDecoder(null);
+ var decoder = inject(new Vt200ProtocolDecoder(null));
verifyPosition(decoder, binary(
"28192030961807208200210101b919011818375801245774036424612500160917000003aa008800007b00aa3429"));
diff --git a/src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java b/src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java
index c03511160..18baf75cb 100644
--- a/src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java
@@ -1,16 +1,16 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class VtfmsFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new VtfmsFrameDecoder();
+ var decoder = inject(new VtfmsFrameDecoder());
assertEquals(
buffer("(863071010087648,0HK44,00,000,14,2,9,,A,114946,180313,11.0244,076.9768,282,000,00000,00000,K,0000128,1,12.8,,200,2.501,,4.001,0,0,0,0,0,0,0,,)105"),
diff --git a/src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java
index 1d4fa7f21..8ca1b9df5 100644
--- a/src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class VtfmsProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class VtfmsProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new VtfmsProtocolDecoder(null);
+ var decoder = inject(new VtfmsProtocolDecoder(null));
verifyPosition(decoder, text(
"(861359037432331,0EF87,00,0,21,2,01,,A,154559,230119,1101.4046,07656.3859,241,000,00078,00000,K,0000812,1,12.7,,,,,,1,0,0,0,1,1,1,+919566531111*+919994462226,)054"),
diff --git a/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java b/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java
index 91bccb4c0..cb20e1b4d 100644
--- a/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class WatchFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,15 @@ public class WatchFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new WatchFrameDecoder();
+ var decoder = inject(new WatchFrameDecoder());
+
+ verifyFrame(
+ binary("5b33472a393730353134313734302a303030392a4c4b2c302c302c35335d"),
+ decoder.decode(null, null, binary("5b33472a393730353134313734302a303030392a4c4b2c302c302c35335d5b33472a393730353134313734302a303035412a55442c3139303732332c3139303730372c412c33362e3831353130392c4e2c31302e313739323331322c452c382e32342c3132372e392c32312e302c352c3130302c35332c302c302c30303030303030302c302c302c35382e305d5b33472a393730353134313734302a303030332a544b515d5b33472a393730353134313734302a303030392a4c4b2c302c302c35335d")));
+
+ verifyFrame(
+ binary("5b33472a3838303930303234322a303133442a55442c3132303632332c3134303032302c412c34382e3934393237332c4e2c20342e333738333036302c452c31382e35362c34332e382c302e302c31322c3130302c37362c3232363132302c302c30303030303030302c322c3235352c3230342c382c333131302c35353032352c3134362c333133302c34393239372c3132342c352c42616e67696e67576966692c33343a61313a65643a65313a39313a34662c2d37312c42415220576946692c33363a61323a65313a65643a61313a64652c2d37322c4e6574776f726b576966692c32363a64653a61313a65643a65313a61302c2d37332c46696265722c33363a61313a65643a65313a39313a34662c2d37352c5b4c475f57616c6c2d4d6f756e7420412f435d653732352c36363a61313a65643a65313a65373a32352c2d38322c31352e305d"),
+ decoder.decode(null, null, binary("5b33472a3838303930303234322a303133442a55442c3132303632332c3134303032302c412c34382e3934393237332c4e2c20342e333738333036302c452c31382e35362c34332e382c302e302c31322c3130302c37362c3232363132302c302c30303030303030302c322c3235352c3230342c382c333131302c35353032352c3134362c333133302c34393239372c3132342c352c42616e67696e67576966692c33343a61313a65643a65313a39313a34662c2d37312c42415220576946692c33363a61323a65313a65643a61313a64652c2d37322c4e6574776f726b576966692c32363a64653a61313a65643a65313a61302c2d37332c46696265722c33363a61313a65643a65313a39313a34662c2d37352c5b4c475f57616c6c2d4d6f756e7420412f435d653732352c36363a61313a65643a65313a65373a32352c2d38322c31352e305d")));
verifyFrame(
binary("5b33472a3335323636313039303134333135302a303030412a4c4b2c302c302c3130305d"),
diff --git a/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java
index 4fab19f26..5fd0ede44 100644
--- a/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java
@@ -1,19 +1,48 @@
package org.traccar.protocol;
-import io.netty.buffer.ByteBuf;
-import org.junit.Test;
-import org.traccar.Context;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
+import org.traccar.database.MediaManager;
import org.traccar.model.Position;
-import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
public class WatchProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new WatchProtocolDecoder(null);
+ var decoder = inject(new WatchProtocolDecoder(null));
+
+ verifyAttribute(decoder, buffer(
+ "[3G*9705141740*000B*oxygen,0,98]"),
+ "bloodOxygen", 98);
+
+ verifyPosition(decoder, buffer(
+ "[3G*9705141740*00C2*UD_LTE,260723,185105,V,00.000000,,00.0000000,,0.00,0.0,0.0,0,100,67,0,0,00000000,2,0,605,1,10006,65799,14,10020,4104,4,3,,34:60:f9:ec:19:f8,-82,,98:48:27:55:18:20,-96,,34:e8:94:e4:06:18,-104,0.0]"));
+
+ verifyPosition(decoder, buffer(
+ "[SG*9059011020*0067*AL,240123,181628,V,54.427538,N,6.409275,W,0.00,0,0,0,19,90,0,0,00000000,1,1,234,10,55C0,3B882A2,132,,10]"));
+
+ verifyPosition(decoder, buffer(
+ "[SG*9059011020*006b*UD2,240123,162011,A,54.427621,N,6.409190,W,0.00,0,0,8,19,88,0,0,00000000,1,1,FFFF,FFFF,FFFE,3B882A2,132,,00]"));
+
+ verifyAttribute(decoder, buffer(
+ "[ZJ*5678901234*0001*0009*TEMP,36.5]"),
+ Position.PREFIX_TEMP + 1, 36.5);
+
+ verifyAttribute(decoder, buffer(
+ "[ZJ*689466020014198*0003*0113*AL,221121,085515,V,00.000000,N,000.000000,E,0,0,0,0,0,44,0,0,00100000,1,255,460,0,16399,234887445,0,6,WIFI00,68:77:24:1b:e7:a7,-59,WIFI01,68:77:24:1b:e3:30,-75,WIFI02,68:77:24:1b:e3:27,-75,WIFI03,00:41:d2:c0:f2:f1,-76,WIFI04,00:41:d2:c0:f2:f0,-77,WIFI05,68:77:24:1b:e3:d8,-82]"),
+ Position.KEY_ALARM, Position.ALARM_REMOVING);
+
+ verifyNull(decoder, binary(
+ "5b5a4a2a3738393436383035303034323639322a303033342a303433392a4a58544b2c302c77617463685f375f32303232303532363039333935342c312c362c2321414d520a0c0a3c3f96d98367e9468ea245320c0a3c3f96d98367e9468ea245320c0a3c3f96d98367e9468ea245320c389814ffcd762fe49d50ae7a2e0cb528aefbf76911df05c2fbe17d050c2200cff77ef0df4d9b4ab9a4340c449814dbe7c63fa82bc3750d800cc48abbffddb0df8e8fda95e5980c49982ff6cf65f9377d02a39c3aaa0c389805f2ff42c1b80e0a0eb1dc0c2998e9defe15cfa3bdbe80d3540c7298c2f6d9239e3eae3c4a81660c490034dbfd513fedad0c2fc3900cc40039b7f71bb0657ba75558c40cd7813b97ff7219777ec7f401260c7d040003bff6f75fdb898a6ba1140cecd127f7f83357cb73a68a5f680cb081d4f6e749e6af8ed367bc480cec1815dfffd2dbed358112af320ccc21179fffbd17a3a61c133b380c920047defc72a784770ec0fe400c383c42f6faebe76fa736e9d1be0c4918e7decddc67ec9afd87ff220cc418e6bffe6cf6c9ac1f83c3900ca6cad1ffe3da24e1be3b547d03c00c6b00b8fee77f60a76d3e7d0292e20c2918b7bfff76387b793d3a36300c7d0400b7fff7f63ae513ac6f74de0c980016fbff7d01f9b30fca67c7220caa982ff6dbd7bf3d8dfed143ec0c44982fdfcb7b517e26f6ea52420c0ed19cfedb438f179d3fc50ec40c008ad2ffff635fe28dc1ec1f860c76cb7d05bffda53eaebe4d201ae20ccccaffbbfd3db4abb6ddf39d0e0c6b00acfeff406fe4a12661caf80c76982fbffffeb17b2f65472f300c7d04c24bf6ef1b10e47f73fc10b40c76036cfecd4e7837145a6a8e900ccccaf2beeba36fbaa36feb60640c7d0400dfffff73bfa3b87d0256a1700c7d04e4efd6efc23b651eb73e77780ccc1813ffffb39f6baa6f3195080c00007afffee0b9df6346ca08d00c6bca7d04feff4d64a7b56f9855da0c769819fbfd954ea5bd7d040ba6420c4c4c09bfffd5f6c57d01930e7d01220cc48a22dffe30bfcbaf08a795140c7d040433b7ff3cba5f3e336a40060cecbd2bfaf775bea7bde7e095ee0cc4caaef7fb623feeaab69eabc20c8c0021bffd1ea4a1b090175a920c7d046445fbdfc1abe910b0ca56160c7d0440cbd7ef03893c7f7d02e1a8c20c85e42dff5fdaa145759d326b5a0ccc4084f75f8eeb7b15e4eb4ff80c6bc22ef7d7eaf8df3b8ff678cc0cca4026f3cf7518fd731ceca3560cec041ffbe7655eaf822f04c4fe0c7d0478e3fbfcb5dfc8a81fdbb9e20cc418e6d7ff777f26affe37cc020cd7977cbff7d0aecb9727be6a0c0c00bde1f2d797fc8754ed09d4ae0cc498279f7e729fcb9eff70c1a60c7d0478e5bfffc67eef953fda69aa0c7200f1bbf7e891ef5a287cb5b80c983629fee5555f739f8a29279a0c76d103bef73f55a6bf89ba8ce40cc46424f6ded9a194167a067d05880cc4780efeffc37fae944d89bfb40c4464bffffb6dd54e8344394a5c0c49781ffffc653feaa31af59ac00cc464cebfd76ae4e8a55d5b5a4a2a3738393436383035303034323639322a303033352a303434332a4a58544b2c302c77617463685f375f32303232303532363039333935342c322c362c5f24fbbc0c7d04983effcfe35fbd8fff7ce6f60c448a1dfbd715bec3b42448e58a0c0e0421bf5f17ebc31a43301bc40c768ababf4f66cf629ee31fe9900c6b6426bf5f4eb7669dacc439140c945733bff9351e7d04ab6be54ef60ccc98bfbffbf67f63b78d8f42880c7d0400c6f7fffab5cbae8e8275da0c0097ffdefff5dfafb0c4727d04980ccc78d1f6ff1a6b7e37631059fa0c760045f3fd853fea877d03aa87440cc40022f7ffa8b5c58f6e80c58e0ccc4c1f9ffff32fa7af87de04560cb09801f6fdd32efcbdad9495b60c6b987d05bff72d61eb687d05a9f9e20cca57c7ffff6cb1fe3387ea596e0c629823dedfbfc50b97965e44ea0c4918ccbfd7cc75e59fff92e9ee0c8c78e7faff707ffda60ec3ada60c30c217befffcb8f3290f06d75e0c0e8a7bb7dff3eec7b7928ef6680c38ca1cdeff272ba012597d051a520c0018dfffeff27d01e369b3bcd7d80c98146eb2fc7f45c38e1ce53e120c3d5700ff7fd44bee28aa089d900c007157bffffe30302d7d0583585c0ccc5747bfe7f73cff7d02de1098240c7d047865f6feca71d70bdfaab6a20cecb946bfd966be74b61a06c6660c441612ffe7eb966a8c2886cf760ccc7827bffd653ff7980a62e9320c00ca98f7fc1b311a3986700cc20c490017bfff70cfe7bb455637320c6228afbf7e6da4c59763b693740cccc2b5fee1951975760e4a9dca0c0000faffdb255f6f86af4be6fc0cccc2ffdfff7d0225efbc847c42760cb48a8fdffbe23ff1a78782cbe60c7d04980cffff6e6dfc75a6c65a500ce62808bfff24f853748a9537400cb4004ebfeb6e70aa4314903e8c0cb46408ff72d62f44945f64897d040cccca7abfff2db5c6bfcc345e700c7d04c24dd6fd5f95638f78974a800cc4caffffffb17d01c36bdd7d047c2e0c7d0436d1f7f8917f83af7fc5c2180c070449f6fe570f128577c8c97d040c7d047813f6df3fd17d026b6790d1b80cc400c9d6d92dc56497843ed10a0c44986effffe13fef8eef7c717a0c7d049872bbfdad3abe2be0d60b240c4900adbf7d02dfa4ef960fdf23580c629845fefc5a650fbf8b0d4cda0c7d040076b7ef273fe78fce983ae40c4a00ded7ff629f7fab4531501c0c6200b7ffedf13fe6a68f01fb6c0cc49809f77fdb91517fb39e8ba00c760009bf7fd6afe7b46921f27a0cecbd1df6faf99120776e807d03fe0c98ca23fbff3749fb5ed3909c160cc44cbbbfffbd70e77d0367bc2e740c499816f77fe2ffe08edd7d048c9e0c940021beff1df0f1338c2f1a3a0c7d040083feebba1c756e5760c2200c94981dfffdf921b92b99909ba40c7d04984ebbdf7ff0c77d025a1fbfc00c7657b3ff77f4befcae2bf625640c62ca53f7fdb35f2e92af3bd5c60c7d049878bbdfc0dfc1bdaa1918000cc404bbbfefb41ee6b50a39bf180c767874f7fb8ee156320ee600020c69981cffffe0fff6bb2764acaa0cec781bfbff7d0324eb9b4b4d5d5b5a4a2a3738393436383035303034323639322a303033362a303433302a4a58544b2c302c77617463685f375f32303232303532363039333935342c332c362c73580c07ca4fbbfff5bec5abcfac465c0c0042a8beff316aed38fe4603dc0c7d04577d04fefdc929f7294ce7520c0c76984dfaff402fe68ebe113b000c7d0436a6fed465ff4f8d8e3306300c44e434f7f79e84abb8fa081be80c983636bef7e128bf7d03d34c71c80cd7982dffd54cac94536beab1320c058bd6bfff701fe69d1a39d1e80c76caedb77ffea0e47febb469440c0098b2bef5e55eed981672b1c40cd800d1bef4bda58daf7d01d309180c08cadffbfc31799f5613fab2da0c7d049828beffa5eea0bd09a14c2e0c0000e59feb5f9dff7f4945e98e0cc40046ffcfe57fb58f7d053dd9e20c7d040047d7ffd38f67aa9db8d38c0c7698d2df5fe2efc6bb0f5a18220c980367bbfd95dae73e3bf2b59a0c49813796fdf5efab9d3ed7d3d80c9800ebd7fdb831ae8f91811e920c7d04ca74bbff5cdcf45605c25f140c013e029fbfe7ffc299376b409a0c7510009e7d02010f68824cccead60cb13b00f7d5821e6c8d594a06880c75ec00f6e782e8f06b0c610d1a0cc09843dfef117fa5b3aef236f40cdcc208ffff4831f83703ca20c00cc09800bf7fd71eec9ba34e3c200c650f6bffd5bc4dbe7ec5b0f1d80c0d1c1f92ef917fa0b96023eac00c8efb1db6bfa42eed9f69051d4e0c8eff23b2fe4486d56ef44f702e0c8ebc1b9657d46eeea852ac337e0c8efb1f96d9877fc9b34c38f1540c121c2796df13577c727f8cedec0ca9107d05afdd6a9d957ab76c02560c121c2dd6bfd33fa5b844f27d02340cb11037b6e3962e6eaf52d6e7460c2b1c3db2dfe61eef9aad3dcc0a0c542e42d763e709fe723a83ae7c0c7cfa56bf7fedb8763c3f8ab2c00ca40022efff2411604d22a485e00c228adcbfdfcd748293c66b0bf20cb10f0097ff806dcf7a0a640d6e0c5a0400b7e3030ef4ae0a6046f80cb82812fe7b04d77e4bab11894a0c541c24b2dd53fea5891e3824420ca9fb26b2d7156fa485049cac420ca91c2d9edb2487526c2e2260fa0ca9bc25b65ff28e41a34232c0f00c8efb25b649e51ec39c0ae6703a0c70f425a6c820dfaf2f8124c8960c80f42794b323aed9ca9b6924be0cb93b278e3e8d929c36bb70b6360c587b27524f85857d056d214841660cda2f278b4c876eb3186e5acc540ce6832f6e3f0d82f81226e6dc3a0c0b922feff50a03d03c98ae28360c03d62befb54ab611de0c8addee0c84d626b7fdb4461556dc0153040c0b0f27ff5781c5c2b32f6762140c49bf2dfaf521969b702ecb11d80c7d050f27cfed75bfab95dc4af3180c011c3d8e7451df80a5cd0948080c7c2e35f2c7b0becca22e50769e0c7c1c3d965e628f46a9a58ae6100c7c2e3b965f4a6b5ebd1436b0b00c7c863eaedf18c7816cdeeed7e20c2b3e3df6b73952b2b1abc048a00c7cfb3db6cd67ae68cda18af9d60c2bff3e96df12ff61b39627cd580c7c863fd6cd810ee595d85ee6645d5b5a4a2a3738393436383035303034323639322a303033372a303433372a4a58544b2c302c77617463685f375f32303232303532363039333935342c342c362c0c7cff3fb65f812fe196dc62d8360c7c2e3db2de738fae9ca7c7236c0c2b2e3d96df6c1d775a3df5a47e0c7c3e3f96fe943dc07e81e170700c75503fb7d6a6197f1b08df85440c5a133ab6d6a0e68f3acb04b7b00cfa293fd6cfc20c390d5265d3c80c581347b278077d03dc22d9e49c680ce64d47924e8dcdffe9be19dc100cb90f4f9e612d2201961c2e111c0c003b4febb58a96c809ab5a71040ce6d759fbddba54b2aa9d9d983e0cc029576ecf1f703099d84994520c4029579e7d0281577073f5629dd80c5a2952b6fed177177d01e57d0175c20cd8647d044f7e3c58aba523ddb0720cb56753d3e9c6799f95938401f60c756414ff5f00fb57bc4d7e111c0c7c085573ef743ee19ca30057e00c752e5ab77e34eec69f3cbe53940c542e4d96d6e7ff03854a9506620c7cff55b6efca197610a86606180c7cfb55b67eb25f4b999c002bf20c7c107d03beeb451fad8d042492740cb8f05eb5ff664f679c1cc991c60ce1671bffd33d9445b57d0584c7d60c07781dfef5e3ee81b45ff8a8c80cc40072b7dfe6fe6e978257253a0cb1131fe6783035868e439b00d80c583b27b17ecb53dd165c3422180c703b2fbeb18d023e14d90304700c3cce2b93cdc2e6b3550a5546160cb13b3b72fe24273859059b52040c224d34edc742f6bb7c877d02b5940cb84d37cdcfcbc3f03a041cf4ac0ca4923a9f3b74e805b235cce8660c759000fbfd90565072aa7d03bb520cb592017f411dcbe80a0cc420360c09d6528fcf2e25b382ee46d75a0ce2e853d3cfb617fd7d023f05e0780c07cc3bbabfa9f6cec5aa48ac600c404208fb678a4cf16a9c09098c0cf14244fbdfc2afe7932fe57d02900c011c369e7d0264a8570a54f9a2e80cb1103daed6249fe59dc888c2ac0cb1103573c5f697be759923ecc80c705f7d059effaaa4b09b976f375a0c804223bbed89767d041693edab180cb49819d7eb5a8573bb10c951540c3c643af74f021f25b6dd3b7d02040c07982bd73fb31fe38f09a227a40c037610ff7d03c6058098fef936a80c03b808debbe055a1a71319128c0c6b8f2e9e3bb52d71c226d3141a0cdab82d7fa9d416167a1cb950020c03c32bb23ee9e3743f3b6853060cc02937adb5157d05f4a6960c1b680c4076365e6b754bda9394a7aa720c06293ef23313fb1b94bcc2c09a0ce676006bbd8e0417941b90d23c0cb9294f7d01fd3d65748cf6d1cc220c03767d035e3a65e6f2514ab1db060ce6d965bf4035f65c79a9e4446a0ce62921dbf46457b56cd65f6c500c584d6bba7ea8166edd6cf7693a0cb939227bfca25f82a7c4202f2e0c06ce2b9a4f0d95f39eb43c22840c06901eef6fd15fe48f452000e00c62023afbffb269beba0ee0ac540ce6ec00f37b8139f2026e80f1440c22501dfe7d017d03ed8c3ff6803f240cc48ae3b7fd725e63a347cd64100c0094f8efdeb0a9f35c83eb06b00c005d5b5a4a2a3738393436383035303034323639322a303033382a303433332a4a58544b2c302c77617463685f375f32303232303532363039333935342c352c362c6647deef2df57fb68fd76b660c44e43cbfefc0beec867d025c3f920cb4507d01ff6f42ee6c1f58a0db0e0c7d045701ff7f19f9f90fdff037c20c4404259efcd47d02a52b7ef6df0e0c7d04d128f3578db14779993109560ce1e41ecffd2851af49256b1ecc0c7d049837ffff707168db3dd1ac240cc09419f7f39a7d013d6ec1b4e55c0cc4881cff5f49f55fadc52285a40c06ce9ad7dbb8349b97031ac3b00c407d049d9bed74dfadad950eab560c06799ffac7a924b18bdf11c3d40c8054a2f777522e65be921a77240c8042a19bff706fe5b7e3e7d0360cd82840bff3f4fe429bea0081560c0064419fd9157f8b9c797e92c20cc47fe2b7d5e6ee45bf0524010e0c0894299e7d037e4553bcbbc0989e0c40501bbbdc926f8daf53885e0a0c80971ffee559f5bf98ed54cf140c00581abbffac75b88b14d5e3780c5a046dd66fd7bfe5b7ca749df40c403672bbcfe47ee797860ded5e0cb5502efb7ee2ffc7bbdc27d0880c44ca08fbf7031ecd9321d21ef40cdc9806fefde36f0699ad1569420c22cb1bfbdc974fcb900ab601440c00cb1cfbdfd2f7d2730b0b46680c0b4203dfef309fe0adc121e2080c225829feeb901f25b926343bae0c624204dfff4875b69ceda4df4c0c499886ffe7301e8e8bf9ef0a260cdce408dbef829fe45337e98d860c010800ef76088d8015f3b2c84e0c755c3ecfc898f50fbcdb9344220c7c7d03459349337d01e4949da1b4ec0c7cf046ae6e4a90df3552070a5e0c7cf045d23fbba0951147986eca0c7536426e6ef2ef0b7d01c22fd2960cb8284e9db92d40552988334f200cb8024acdbfea90d13b545fe35e0cb8f04d5e48659d48b97c1096140c7c084f79df4402702126bf358a0cb8a74d4def66535e145638d12e0c543e4d8edfa2531b15a340eb800cb83e4eafbd9031291a8563e4780c54a74ef1c7300da79aa94bb67d050cb8f04eba6fb0325813871511b80ce20ff6fffd404ed58ecf264c8e0c7c0f1cb3fe1a36fb7187c379d00c7c3e52f6727d0261ca8bdd1361b80cb8d64d9a4fb1cfe0aadaaa7d05c40c2b2e44b2bfb9b4dcad9d7d0200280c7c3b47d5db803fc2aee71a77f00c7c1343b2bfa06ee6ad3228f10a0c7c3b4a76477fe7650b0c809ca80c54d74b92dbc327134514d6126e0c7c5f4a8f4f74efaaa5cd0a43bc0c7c104bb64ff5ce604fa2028b680c7cff4aaec7f7a9394cc4c599e60cb8ce52eeb553d215a6a466b4120c750f4fae5f9816c04a0a3f751e0c75e04f73c58e96bb4b925a4c680cb80f4b6e3fe1635614bbdeccbc0c7c3b4faf7e825e42d473ee76800ce298578ffcb61f0af936387bbe0cb800e39bf62410681583e0d2b20cb4987d05ff7f297bf69eaf4cd8b40cb57815bf7f300fcffe9fae966a0cb497acd75fd37f648d00d141a00cc48af9fffe1a3b979b8f8573e80c29bff1bf4b94c6fd7c3eec075e0c7cce1f5d5b5a4a2a3738393436383035303034323639322a303033392a303065352a4a58544b2c302c77617463685f375f32303232303532363039333935342c362c362c8f5cf9f34fa6edceb18c0ca4ce436e7d02d329de94b63eb11a0cb894438f44cf753dbc1a83b4560cb8e44391eff729d4155a231bf40cb59443f373b4288492cd6e38160c5a42049bfec8678ad42bce0c560cb12e39fec3d1fe24b5572ee0be0cb1ce35fe33688455aa74e3ffa40cb1d635df4b704160ae864a7d03440cb10f3267dbf4a21d540ca1051c0cb11337724f8747f5547d054e91660cb1a73692df964f3bbb0758d41a0cfe05b60c314460297eae4185f20cad673ceb6dfa05ddbe0278d5de5d"));
+
+ verifyPosition(decoder, buffer(
+ "[3G*9031853319*004E*UD2,220322,055105,A,22.761162,N,114.360192,E,0,0,47,14,100,64,0,0,00000008,0,0]"));
verifyAttribute(decoder, buffer(
"[3G*2104326058*000E*btemp2,1,35.29]"),
@@ -134,22 +163,26 @@ public class WatchProtocolDecoderTest extends ProtocolTest {
verifyPosition(decoder, buffer(
"[ZJ*014111001350304*0038*008a*UD,070318,021027,V,00.000000,N,000.000000,E,0,0,0,0,100,18,1000,50,00000000,4,255,460,0,9346,5223,42,9346,5214,20,9784,4083,11,9346,5221,5]"));
+
+ verifyPosition(decoder, buffer(
+ "[3G*8800000015*00DD*UD,010120,025946,V,0.0,N,0.0,E,22.0,0,-1,0,100,98,0,0,00000000,0,5,eduroam,f4:db:e6:d2:a8:00,-53,eduroam,f4:db:e6:da:d0:80,-79,eduroam,78:0c:f0:24:f9:80,-82,Lions,b0:be:76:0a:05:9a,-82,tubs-guest,f4:db:e6:d2:a8:01,-53,0.0]"));
}
@Test
public void testDecodeVoiceMessage() throws Exception {
- var decoder = new WatchProtocolDecoder(null);
-
- verifyNull(decoder.decode(null, null, buffer("[CS*1234567890*0004*TK,1]")));
+ var decoder = inject(new WatchProtocolDecoder(null));
- ByteBuf data = binary("7d5b5d2c2aff");
+ var mediaManager = mock(MediaManager.class);
+ when(mediaManager.writeFile(any(), any(), any())).thenReturn("mock.amr");
+ decoder.setMediaManager(mediaManager);
- Object decodedObject = decoder.decode(null, null, concatenateBuffers(buffer("[CS*1234567890*000e*TK,#!AMR"), data.resetReaderIndex(), buffer("]")));
- assertEquals("1234567890/mock.amr", ((Position) decodedObject).getAttributes().get("audio"));
+ verifyAttribute(decoder, concatenateBuffers(
+ buffer("[CS*1234567890*000e*TK,#!AMR"), binary("7d5b5d2c2aff"), buffer("]")),
+ Position.KEY_AUDIO, "mock.amr");
- verifyFrame(concatenateBuffers(buffer("#!AMR"), data.resetReaderIndex()), ((MockMediaManager) Context.getMediaManager()).readFile("1234567890/mock.amr"));
+ verify(mediaManager).writeFile(any(), any(), any());
}
diff --git a/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java
index bcfc8df41..649c0016b 100644
--- a/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -9,7 +9,7 @@ public class WatchProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new WatchProtocolEncoder(null);
+ var encoder = inject(new WatchProtocolEncoder(null));
Command command;
@@ -58,9 +58,9 @@ public class WatchProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeTimezone() {
+ public void testEncodeTimezone() throws Exception {
- var encoder = new WatchProtocolEncoder(null);
+ var encoder = inject(new WatchProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java
index 12724c32f..b7c422456 100644
--- a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class WialonProtocolDecoderTest extends ProtocolTest {
@@ -8,11 +8,15 @@ public class WialonProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new WialonProtocolDecoder(null);
+ var decoder = inject(new WialonProtocolDecoder(null));
verifyNull(decoder, text(
"#L#2.0;42001300083;;CE45"));
+ verifyAttribute(decoder, text(
+ "#D#220323;114150;2234.80479;N;11354.87786;E;0;NA;59;11;NA;NA;NA;;NA;d_battr:1:94,d_csq:1:21,di_light:1:1;E7C9"),
+ "di_light", 1.0);
+
verifyAttributes(decoder, text(
"#D#NA;NA;5429.681944502211763;N;02654.60403650999069;E;NA;NA;NA;NA;NA;NA;NA;1.0;NA;m1:1:9196679,d1:1:15397,t1:1:20,b1:1:162,fuel1:2:21588.0,pv1:2:35.98,finish:1:1;0x9b0"));
@@ -75,6 +79,9 @@ public class WialonProtocolDecoderTest extends ProtocolTest {
verifyPositions(decoder, text(
"#B#110315;045857;5364.0167;N;06127.8262;E;0;155;965;7;2.40;4;0;14.77,0.02,3.6;AB45DF01145;"));
+ verifyAttribute(decoder, text(
+ "#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;motion:3:false"),
+ "motion", false);
}
}
diff --git a/src/test/java/org/traccar/protocol/WliFrameDecoderTest.java b/src/test/java/org/traccar/protocol/WliFrameDecoderTest.java
index 2e0d86a61..405fc340e 100644
--- a/src/test/java/org/traccar/protocol/WliFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WliFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class WliFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class WliFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new WliFrameDecoder();
+ var decoder = inject(new WliFrameDecoder());
verifyFrame(
binary("0231000101bba758c900010034000500ff001001258fc9013e80ed00001183350101e20006003200090030000a0032000b003331000c0031000d00343438000e003530000f003100100031303800130032001b003134001c0033392c33352c32382c33382c34302c33372c33332c33382c33352c34322c33372c3335001d003130001e0038002300343235002400303100250031303432320026003336343733002700323800280037002900312c312c312c312c31302e3232352e3135312e3230342c36353533352c302c39392c39392c3235352c3235352c3235352c323535002a0030002c0030003000300032003000330031003400ff001c0214130502061b0101258fc9013e80ed000001e2000000000000004d004500302c323031392f30352f30322c30363a33333a30302c323031392f30352f30322c30363a32363a3230005a003000f100352c302c342c302c2d312c2d3100f2003300f3003100f50038363634323530333137303639323400f600312c302c302c3431322c3000f70038343437373200f80032312c31312c302c302c302c302c2c2c2c2c2c302c3000f9003300fa00393100fb0032313100fc0032313000ff00313535363737383533340003"),
diff --git a/src/test/java/org/traccar/protocol/WliProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WliProtocolDecoderTest.java
index 6f86a9fd9..482c15da0 100644
--- a/src/test/java/org/traccar/protocol/WliProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WliProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class WliProtocolDecoderTest extends ProtocolTest {
@@ -8,11 +8,14 @@ public class WliProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new WliProtocolDecoder(null);
+ var decoder = inject(new WliProtocolDecoder(null));
verifyNull(decoder, binary(
"0232776c693a30343930333332303332343103"));
+ verifyAttributes(decoder, binary(
+ "0231000101536c27e40001003400dbd20030363a34323a303000dbd30030352f30322f31390004002d3100060030000a00343235000b003031000c003130343232000d003336343733000e003239000f0037001000312c312c312c312c31302e3230322e33342e33312c36353533352c302c39392c39392c3235352c3235352c3235352c323535001100300013003000140033001500343237001600333700170031001800313038001900320031003000320030004500302c323031392f30352f30322c30363a34313a34312c323031392f30352f30322c30363a33353a303800f100342c302c332c302c2d312c2d3100f2003300f3003100f50038363634323530333137303639323400f600312c302c302c3431322c3000f70038343437373200f800302c3330302c302c302c302c302c2c2c2c2c2c302c3000f9003300fa00393100fb0032313100fc0032313000ff00313535363737393332300003"));
+
verifyPosition(decoder, binary(
"0231000101bba758c900010034000500ff001001258fc9013e80ed00001183350101e20006003200090030000a0032000b003331000c0031000d00343438000e003530000f003100100031303800130032001b003134001c0033392c33352c32382c33382c34302c33372c33332c33382c33352c34322c33372c3335001d003130001e0038002300343235002400303100250031303432320026003336343733002700323800280037002900312c312c312c312c31302e3232352e3135312e3230342c36353533352c302c39392c39392c3235352c3235352c3235352c323535002a0030002c0030003000300032003000330031003400ff001c0214130502061b0101258fc9013e80ed000001e2000000000000004d004500302c323031392f30352f30322c30363a33333a30302c323031392f30352f30322c30363a32363a3230005a003000f100352c302c342c302c2d312c2d3100f2003300f3003100f50038363634323530333137303639323400f600312c302c302c3431322c3000f70038343437373200f80032312c31312c302c302c302c302c2c2c2c2c2c302c3000f9003300fa00393100fb0032313100fc0032313000ff00313535363737383533340003"));
diff --git a/src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java b/src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java
index 85a878aef..f1f65cb2c 100644
--- a/src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
public class WondexFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new WondexFrameDecoder();
+ var decoder = inject(new WondexFrameDecoder());
assertNull(
decoder.decode(null, null, binary("f0d70b0001ca9a3b")));
diff --git a/src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java
index 111cc9fbe..8f86263c4 100644
--- a/src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class WondexProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class WondexProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new WondexProtocolDecoder(null);
+ var decoder = inject(new WondexProtocolDecoder(null));
verifyPosition(decoder, buffer(
"2005010051,19990925063830,26.106181,44.440225,0,0,0,7,2,0.0,0,,,0"));
diff --git a/src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java
index ed0af844e..2e1a45c8c 100644
--- a/src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java
@@ -1,16 +1,16 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class WondexProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new WondexProtocolEncoder(null);
+ var encoder = inject(new WondexProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(2);
diff --git a/src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java
index 10381168e..ba40486a6 100644
--- a/src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class WristbandProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class WristbandProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new WristbandProtocolDecoder(null);
+ var decoder = inject(new WristbandProtocolDecoder(null));
verifyNotNull(decoder, binary(
"000102004459583836383730343034343735303035357c56312e307c317c7b4630342331382c30372c332c3539303139322c33303a31382c30372c332c3539303139322c33307d0d0afffefc"));
diff --git a/src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java
index aeca95376..9e909f1ca 100644
--- a/src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Xexun2FrameDecoderTest extends ProtocolTest {
@@ -8,12 +8,16 @@ public class Xexun2FrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Xexun2FrameDecoder();
+ var decoder = inject(new Xexun2FrameDecoder());
verifyFrame(
binary("faaf0014000286147503139003400032f2b001002f4260b0d6a0008019104a3378323130333135317c323130333132303100704020308715758089502023015648643670faaf"),
decoder.decode(null, null, binary("faaf0014000286147503139003400032f2b001002f4260b0d6a0008019104a3378323130333135317c323130333132303100704020308715758089502023015648643670faaf")));
+ verifyFrame(
+ binary("FAAF123456FAAF123456FBBF123456FAAF"),
+ decoder.decode(null, null, binary("FAAF123456FBBF01123456FBBF02123456FAAF")));
+
}
}
diff --git a/src/test/java/org/traccar/protocol/Xexun2FrameEncoderTest.java b/src/test/java/org/traccar/protocol/Xexun2FrameEncoderTest.java
new file mode 100644
index 000000000..27e894705
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/Xexun2FrameEncoderTest.java
@@ -0,0 +1,21 @@
+package org.traccar.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+
+public class Xexun2FrameEncoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ Xexun2FrameEncoder encoder = new Xexun2FrameEncoder();
+
+ ByteBuf result = Unpooled.buffer();
+ encoder.encode(null, binary("FAAF123456FAAF123456FBBF123456FAAF"), result);
+ verifyFrame(binary("FAAF123456FBBF01123456FBBF02123456FAAF"), result);
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/Xexun2ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Xexun2ProtocolDecoderTest.java
index 9faccec01..b373c8283 100644
--- a/src/test/java/org/traccar/protocol/Xexun2ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Xexun2ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Xexun2ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Xexun2ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Xexun2ProtocolDecoder(null);
+ var decoder = inject(new Xexun2ProtocolDecoder(null));
verifyPositions(decoder, false, binary(
"faaf00140a5a8618810536243350005ed8e101005b64622880401b001482060864cc2296f840daa22aa884f008c87483c291efddc4f09fc2f49db3c058ef68005a9abe1ae8299d6449bac4e984e0c1d6baa8469d265ff2b60100cc00080000fb2e0013572a3600000002000000000000faaf"));
@@ -25,6 +25,10 @@ public class Xexun2ProtocolDecoderTest extends ProtocolTest {
verifyPositions(decoder, binary(
"FAAF00140CF18626490454584530002BF2DD0200130013D360EFD7F514006402010D46322C4A450BA026D460EFD7FA14006402010D46322C4A450BA026FAAF"));
+ verifyPositions(decoder, binary(
+ "FAAF0014000C8622050512345670002DF3A001002A0062D9047400005E0280001E47001B400D4BA732DF505E40B4153AAF78FEF00109000000000042B36666FAAF"),
+ position("2022-07-21 07:47:00.000", true, 51.68715, 0.06103));
+
}
}
diff --git a/src/test/java/org/traccar/protocol/Xexun2ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Xexun2ProtocolEncoderTest.java
new file mode 100644
index 000000000..62d511c0b
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/Xexun2ProtocolEncoderTest.java
@@ -0,0 +1,29 @@
+package org.traccar.protocol;
+
+import org.junit.jupiter.api.Test;
+import org.traccar.ProtocolTest;
+import org.traccar.model.Command;
+
+public class Xexun2ProtocolEncoderTest extends ProtocolTest {
+
+ @Test
+ public void testEncode() throws Exception {
+
+ var encoder = inject(new Xexun2ProtocolEncoder(null));
+
+ Command command;
+
+ command = new Command();
+ command.setDeviceId(1);
+ command.setType(Command.TYPE_POWER_OFF);
+ verifyCommand(encoder, command, binary("FAAF0007000112345678901234500004FEBC6F663D31FAAF"));
+
+ command = new Command();
+ command.setDeviceId(1);
+ command.setType(Command.TYPE_POSITION_PERIODIC);
+ command.set(Command.KEY_FREQUENCY, 150);
+ verifyCommand(encoder, command, binary("FAAF0007000112345678901234500015F90E747261636B696E675F73656E643D3135302C313530FAAF"));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java b/src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java
index 43b8bdc0e..82287f6ad 100644
--- a/src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class XexunFrameDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class XexunFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new XexunFrameDecoder();
+ var decoder = inject(new XexunFrameDecoder());
verifyFrame(
binary("4750524d432c3230353933352e3030302c412c353134302e343335302c4e2c3530312e303638362c452c302e30302c302e30302c3132313031352c30302c303030302e302c412a37302c462c2c696d65693a3335393538373031343731383339322c"),
diff --git a/src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java
index d2caa9c55..7331827f0 100644
--- a/src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java
@@ -1,14 +1,14 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class XexunProtocolDecoderTest extends ProtocolTest {
@Test
- public void testDecode() throws Exception {
+ public void testDecodeSimple() throws Exception {
- var decoder = new XexunProtocolDecoder(null, false);
+ var decoder = inject(new XexunProtocolDecoder(null, false));
verifyAttributes(decoder, text(
"GPRMC,.000,A,0.000000,S,0.0000,W,0.00,0.00,,00,0000.0,A*55,L,,imei:353579010727036,"));
@@ -53,7 +53,12 @@ public class XexunProtocolDecoderTest extends ProtocolTest {
verifyPosition(decoder, text(
"GPRMC,043435.000,A,811.299200,S,11339.9500,E,0.93,29.52,160313,00,0000.0,A*65,F,,imei:359585014597923,"));
- decoder = new XexunProtocolDecoder(null, true);
+ }
+
+ @Test
+ public void testDecodeFull() throws Exception {
+
+ var decoder = inject(new XexunProtocolDecoder(null, true));
verifyPosition(decoder, text(
"171007160505,,GPRMC,160505.000,A,5323.4680,N,00252.4202,W,000.0,129.7,071017,,,A*7A,F,ACCStart, imei:864504031916915,10,41.1,F:4.28V,1,135,19824,234,15,0062,B7D5"));
diff --git a/src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java
index f3a56a79d..8f912d9e2 100644
--- a/src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class XirgoProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class XirgoProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecodeCustom() throws Exception {
- var decoder = new XirgoProtocolDecoder(null);
+ var decoder = inject(new XirgoProtocolDecoder(null));
decoder.setForm("UID,EV,D,T,LT,LN,AL,GSPT,HD,SV,HP,BV,CQ,GS,SI,IG,OT");
@@ -31,7 +31,7 @@ public class XirgoProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecodeNew() throws Exception {
- var decoder = new XirgoProtocolDecoder(null);
+ var decoder = inject(new XirgoProtocolDecoder(null));
verifyPosition(decoder, text(
"$$352054058132185,4001,2017/04/21,00:01:05,32.54659,-116.90670,143.2,0,0,0,598,0.0,12,0.9,765840,7.0,14.5,19,1,1,0011,8.5,63.2,5,21999,184,255,671,207,100,185##"));
@@ -59,7 +59,7 @@ public class XirgoProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecodeOld() throws Exception {
- var decoder = new XirgoProtocolDecoder(null);
+ var decoder = inject(new XirgoProtocolDecoder(null));
verifyPosition(decoder, text(
"$$354660046140722,6001,2013/01/22,15:36:18,25.80907,-80.32531,7.1,19,165.2,11,0.8,11.1,17,1,1,3.9,2##"),
diff --git a/src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java
index 4f01aa72b..2efedf51a 100644
--- a/src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class XirgoProtocolEncoderTest extends ProtocolTest {
@Test
public void testEncode() throws Exception {
- var encoder = new XirgoProtocolEncoder(null);
+ var encoder = inject(new XirgoProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java
index 3197ba854..fae163a56 100644
--- a/src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Xrb28ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Xrb28ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Xrb28ProtocolDecoder(null);
+ var decoder = inject(new Xrb28ProtocolDecoder(null));
verifyAttributes(decoder, text(
"*SCOR,OM,123456789123456,Q0,412,80,28#"));
diff --git a/src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java
index 357da8f7b..eaa29a833 100644
--- a/src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java
@@ -1,17 +1,17 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class Xrb28ProtocolEncoderTest extends ProtocolTest {
@Test
- public void testEncodePositionPeriodic() {
+ public void testEncodePositionPeriodic() throws Exception {
- var encoder = new Xrb28ProtocolEncoder(null);
+ var encoder = inject(new Xrb28ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
@@ -23,9 +23,9 @@ public class Xrb28ProtocolEncoderTest extends ProtocolTest {
}
@Test
- public void testEncodeCustom() {
+ public void testEncodeCustom() throws Exception {
- var encoder = new Xrb28ProtocolEncoder(null);
+ var encoder = inject(new Xrb28ProtocolEncoder(null));
Command command = new Command();
command.setDeviceId(1);
diff --git a/src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java
index f8ddd35c3..43c1f0676 100644
--- a/src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Xt013ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Xt013ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Xt013ProtocolDecoder(null);
+ var decoder = inject(new Xt013ProtocolDecoder(null));
verifyPosition(decoder, text(
"TK,862950021650364,150131090859,+53.267863,+5.767363,0,38,12,0,F,204,08,C94,336C,24,,4.09,1,,,,,,,,"),
diff --git a/src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java
index 1b3f6fcbb..881ff1ee9 100644
--- a/src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class Xt2400ProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class Xt2400ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Xt2400ProtocolDecoder(null);
+ var decoder = inject(new Xt2400ProtocolDecoder(null));
decoder.setConfig("\n:wycfg pcr[1] 012801030405060708090a1213c8545657585a656e7d2cd055595d5e71797a7b7c7e7f80818285866b\n");
diff --git a/src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java
index 1d29b1282..a5a2a11d1 100644
--- a/src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java
@@ -1,6 +1,6 @@
package org.traccar.protocol;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.traccar.ProtocolTest;
public class YwtProtocolDecoderTest extends ProtocolTest {
@@ -8,7 +8,7 @@ public class YwtProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new YwtProtocolDecoder(null);
+ var decoder = inject(new YwtProtocolDecoder(null));
verifyPosition(decoder, text(
"%RP,1222102985:1,170509033842,E102.146563,N14.582175,,0,320,10,0,00-00-00-00-00-00-00-00-00-00-00-00,,1db2-02b3-52004,3>941.523-32,7>1,19>-16,20>30.9V"));
diff --git a/src/test/java/org/traccar/reports/ReportUtilsTest.java b/src/test/java/org/traccar/reports/ReportUtilsTest.java
index deb17ddd2..0f14577fd 100644
--- a/src/test/java/org/traccar/reports/ReportUtilsTest.java
+++ b/src/test/java/org/traccar/reports/ReportUtilsTest.java
@@ -1,29 +1,49 @@
package org.traccar.reports;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import org.apache.velocity.app.VelocityEngine;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.traccar.BaseTest;
+import org.traccar.api.security.PermissionsService;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Device;
+import org.traccar.model.Position;
+import org.traccar.reports.common.ReportUtils;
+import org.traccar.reports.model.StopReportItem;
+import org.traccar.reports.model.TripReportItem;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.TimeZone;
-import org.junit.Test;
-import org.traccar.BaseTest;
-import org.traccar.TestIdentityManager;
-import org.traccar.model.Position;
-import org.traccar.reports.model.StopReport;
-import org.traccar.reports.model.TripReport;
-import org.traccar.reports.model.TripsConfig;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class ReportUtilsTest extends BaseTest {
+
+ private Storage storage;
+
+ @BeforeEach
+ public void init() throws StorageException {
+ storage = mock(Storage.class);
+ when(storage.getObject(eq(Device.class), any())).thenReturn(mock(Device.class));
+ }
private Date date(String time) throws ParseException {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
@@ -38,35 +58,51 @@ public class ReportUtilsTest extends BaseTest {
position.setTime(date(time));
position.setValid(true);
position.setSpeed(speed);
+ position.set(Position.KEY_MOTION, speed > 0);
position.set(Position.KEY_TOTAL_DISTANCE, totalDistance);
return position;
}
+ private Device mockDevice(
+ double minimalTripDistance, long minimalTripDuration, long minimalParkingDuration,
+ long minimalNoDataDuration, boolean useIgnition) {
+ Device device = mock(Device.class);
+ when(device.getAttributes()).thenReturn(Map.of(
+ Keys.REPORT_TRIP_MINIMAL_TRIP_DISTANCE.getKey(), minimalTripDistance,
+ Keys.REPORT_TRIP_MINIMAL_TRIP_DURATION.getKey(), minimalTripDuration,
+ Keys.REPORT_TRIP_MINIMAL_PARKING_DURATION.getKey(), minimalParkingDuration,
+ Keys.REPORT_TRIP_MINIMAL_NO_DATA_DURATION.getKey(), minimalNoDataDuration,
+ Keys.REPORT_TRIP_USE_IGNITION.getKey(), useIgnition));
+ return device;
+ }
+
@Test
public void testCalculateDistance() {
Position startPosition = new Position();
startPosition.set(Position.KEY_TOTAL_DISTANCE, 500.0);
Position endPosition = new Position();
endPosition.set(Position.KEY_TOTAL_DISTANCE, 700.0);
- assertEquals(ReportUtils.calculateDistance(startPosition, endPosition), 200.0, 10);
+ assertEquals(PositionUtil.calculateDistance(startPosition, endPosition, true), 200.0, 10);
startPosition.set(Position.KEY_ODOMETER, 50000);
endPosition.set(Position.KEY_ODOMETER, 51000);
- assertEquals(ReportUtils.calculateDistance(startPosition, endPosition), 1000.0, 10);
+ assertEquals(PositionUtil.calculateDistance(startPosition, endPosition, true), 1000.0, 10);
}
@Test
public void testCalculateSpentFuel() {
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null);
Position startPosition = new Position();
Position endPosition = new Position();
- assertEquals(ReportUtils.calculateFuel(startPosition, endPosition), 0.0, 0.01);
+ assertEquals(reportUtils.calculateFuel(startPosition, endPosition), 0.0, 0.01);
startPosition.set(Position.KEY_FUEL_LEVEL, 0.7);
endPosition.set(Position.KEY_FUEL_LEVEL, 0.5);
- assertEquals(ReportUtils.calculateFuel(startPosition, endPosition), 0.2, 0.01);
+ assertEquals(reportUtils.calculateFuel(startPosition, endPosition), 0.2, 0.01);
}
@Test
- public void testDetectTripsSimple() throws ParseException {
+ public void testDetectTripsSimple() throws Exception {
List<Position> data = Arrays.asList(
position("2016-01-01 00:00:00.000", 0, 0),
@@ -75,18 +111,20 @@ public class ReportUtilsTest extends BaseTest {
position("2016-01-01 00:03:00.000", 10, 1000),
position("2016-01-01 00:04:00.000", 10, 2000),
position("2016-01-01 00:05:00.000", 0, 3000),
- position("2016-01-01 00:06:00.000", 0, 3000),
- position("2016-01-01 00:07:00.000", 0, 3000));
+ position("2016-01-01 00:15:00.000", 0, 3000),
+ position("2016-01-01 00:25:00.000", 0, 3000));
+ when(storage.getObjects(eq(Position.class), any())).thenReturn(data);
- TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false, 0.01);
+ Device device = mockDevice(500, 300, 180, 900, false);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null);
- Collection<TripReport> trips = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, TripReport.class);
+ var trips = reportUtils.slowTripsAndStops(device, new Date(), new Date(), TripReportItem.class);
assertNotNull(trips);
assertFalse(trips.isEmpty());
- TripReport itemTrip = trips.iterator().next();
+ TripReportItem itemTrip = trips.iterator().next();
assertEquals(date("2016-01-01 00:02:00.000"), itemTrip.getStartTime());
assertEquals(date("2016-01-01 00:05:00.000"), itemTrip.getEndTime());
@@ -95,15 +133,14 @@ public class ReportUtilsTest extends BaseTest {
assertEquals(10, itemTrip.getMaxSpeed(), 0.01);
assertEquals(3000, itemTrip.getDistance(), 0.01);
- Collection<StopReport> stops = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class);
+ var stops = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class);
assertNotNull(stops);
assertFalse(stops.isEmpty());
- Iterator<StopReport> iterator = stops.iterator();
+ Iterator<StopReportItem> iterator = stops.iterator();
- StopReport itemStop = iterator.next();
+ StopReportItem itemStop = iterator.next();
assertEquals(date("2016-01-01 00:00:00.000"), itemStop.getStartTime());
assertEquals(date("2016-01-01 00:02:00.000"), itemStop.getEndTime());
@@ -112,13 +149,13 @@ public class ReportUtilsTest extends BaseTest {
itemStop = iterator.next();
assertEquals(date("2016-01-01 00:05:00.000"), itemStop.getStartTime());
- assertEquals(date("2016-01-01 00:07:00.000"), itemStop.getEndTime());
- assertEquals(120000, itemStop.getDuration());
+ assertEquals(date("2016-01-01 00:25:00.000"), itemStop.getEndTime());
+ assertEquals(1200000, itemStop.getDuration());
}
@Test
- public void testDetectTripsSimpleWithIgnition() throws ParseException {
+ public void testDetectTripsSimpleWithIgnition() throws Exception {
List<Position> data = Arrays.asList(
position("2016-01-01 00:00:00.000", 0, 0),
@@ -127,20 +164,22 @@ public class ReportUtilsTest extends BaseTest {
position("2016-01-01 00:03:00.000", 10, 1000),
position("2016-01-01 00:04:00.000", 10, 2000),
position("2016-01-01 00:05:00.000", 0, 3000),
- position("2016-01-01 00:06:00.000", 0, 3000),
- position("2016-01-01 00:07:00.000", 0, 3000));
+ position("2016-01-01 00:15:00.000", 0, 3000),
+ position("2016-01-01 00:25:00.000", 0, 3000));
+ when(storage.getObjects(eq(Position.class), any())).thenReturn(data);
data.get(5).set(Position.KEY_IGNITION, false);
- TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, true, false, 0.01);
+ Device device = mockDevice(500, 300, 180, 900, true);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null);
- Collection<TripReport> trips = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, TripReport.class);
+ var trips = reportUtils.slowTripsAndStops(device, new Date(), new Date(), TripReportItem.class);
assertNotNull(trips);
assertFalse(trips.isEmpty());
- TripReport itemTrip = trips.iterator().next();
+ TripReportItem itemTrip = trips.iterator().next();
assertEquals(date("2016-01-01 00:02:00.000"), itemTrip.getStartTime());
assertEquals(date("2016-01-01 00:05:00.000"), itemTrip.getEndTime());
@@ -149,8 +188,7 @@ public class ReportUtilsTest extends BaseTest {
assertEquals(10, itemTrip.getMaxSpeed(), 0.01);
assertEquals(3000, itemTrip.getDistance(), 0.01);
- trips = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, TripReport.class);
+ trips = reportUtils.slowTripsAndStops(device, new Date(), new Date(), TripReportItem.class);
assertNotNull(trips);
assertFalse(trips.isEmpty());
@@ -164,15 +202,14 @@ public class ReportUtilsTest extends BaseTest {
assertEquals(10, itemTrip.getMaxSpeed(), 0.01);
assertEquals(3000, itemTrip.getDistance(), 0.01);
- Collection<StopReport> stops = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class);
+ var stops = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class);
assertNotNull(stops);
assertFalse(stops.isEmpty());
- Iterator<StopReport> iterator = stops.iterator();
+ Iterator<StopReportItem> iterator = stops.iterator();
- StopReport itemStop = iterator.next();
+ StopReportItem itemStop = iterator.next();
assertEquals(date("2016-01-01 00:00:00.000"), itemStop.getStartTime());
assertEquals(date("2016-01-01 00:02:00.000"), itemStop.getEndTime());
@@ -181,13 +218,13 @@ public class ReportUtilsTest extends BaseTest {
itemStop = iterator.next();
assertEquals(date("2016-01-01 00:05:00.000"), itemStop.getStartTime());
- assertEquals(date("2016-01-01 00:07:00.000"), itemStop.getEndTime());
- assertEquals(120000, itemStop.getDuration());
+ assertEquals(date("2016-01-01 00:25:00.000"), itemStop.getEndTime());
+ assertEquals(1200000, itemStop.getDuration());
}
@Test
- public void testDetectTripsWithFluctuation() throws ParseException {
+ public void testDetectTripsWithFluctuation() throws Exception {
List<Position> data = Arrays.asList(
position("2016-01-01 00:00:00.000", 0, 0),
@@ -200,18 +237,20 @@ public class ReportUtilsTest extends BaseTest {
position("2016-01-01 00:07:00.000", 0, 5000),
position("2016-01-01 00:08:00.000", 10, 6000),
position("2016-01-01 00:09:00.000", 0, 7000),
- position("2016-01-01 00:10:00.000", 0, 7000),
- position("2016-01-01 00:11:00.000", 0, 7000));
+ position("2016-01-01 00:19:00.000", 0, 7000),
+ position("2016-01-01 00:29:00.000", 0, 7000));
+ when(storage.getObjects(eq(Position.class), any())).thenReturn(data);
- TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false, 0.01);
+ Device device = mockDevice(500, 300, 180, 900, false);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null);
- Collection<TripReport> trips = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, TripReport.class);
+ var trips = reportUtils.slowTripsAndStops(device, new Date(), new Date(), TripReportItem.class);
assertNotNull(trips);
assertFalse(trips.isEmpty());
- TripReport itemTrip = trips.iterator().next();
+ TripReportItem itemTrip = trips.iterator().next();
assertEquals(date("2016-01-01 00:02:00.000"), itemTrip.getStartTime());
assertEquals(date("2016-01-01 00:09:00.000"), itemTrip.getEndTime());
@@ -220,15 +259,14 @@ public class ReportUtilsTest extends BaseTest {
assertEquals(10, itemTrip.getMaxSpeed(), 0.01);
assertEquals(7000, itemTrip.getDistance(), 0.01);
- Collection<StopReport> stops = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class);
+ var stops = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class);
assertNotNull(stops);
assertFalse(stops.isEmpty());
- Iterator<StopReport> iterator = stops.iterator();
+ Iterator<StopReportItem> iterator = stops.iterator();
- StopReport itemStop = iterator.next();
+ StopReportItem itemStop = iterator.next();
assertEquals(date("2016-01-01 00:00:00.000"), itemStop.getStartTime());
assertEquals(date("2016-01-01 00:02:00.000"), itemStop.getEndTime());
@@ -237,31 +275,33 @@ public class ReportUtilsTest extends BaseTest {
itemStop = iterator.next();
assertEquals(date("2016-01-01 00:09:00.000"), itemStop.getStartTime());
- assertEquals(date("2016-01-01 00:11:00.000"), itemStop.getEndTime());
- assertEquals(120000, itemStop.getDuration());
+ assertEquals(date("2016-01-01 00:29:00.000"), itemStop.getEndTime());
+ assertEquals(1200000, itemStop.getDuration());
}
@Test
- public void testDetectStopsOnly() throws ParseException {
+ public void testDetectStopsOnly() throws Exception {
- Collection<Position> data = Arrays.asList(
+ var data = Arrays.asList(
position("2016-01-01 00:00:00.000", 0, 0),
position("2016-01-01 00:01:00.000", 0, 0),
position("2016-01-01 00:02:00.000", 1, 0),
position("2016-01-01 00:03:00.000", 0, 0),
position("2016-01-01 00:04:00.000", 1, 0),
position("2016-01-01 00:05:00.000", 0, 0));
+ when(storage.getObjects(eq(Position.class), any())).thenReturn(data);
- TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01);
+ Device device = mockDevice(500, 300, 200, 900, false);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null);
- Collection<StopReport> result = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class);
+ var result = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class);
assertNotNull(result);
assertFalse(result.isEmpty());
- StopReport itemStop = result.iterator().next();
+ StopReportItem itemStop = result.iterator().next();
assertEquals(date("2016-01-01 00:00:00.000"), itemStop.getStartTime());
assertEquals(date("2016-01-01 00:05:00.000"), itemStop.getEndTime());
@@ -270,25 +310,27 @@ public class ReportUtilsTest extends BaseTest {
}
@Test
- public void testDetectStopsWithTripCut() throws ParseException {
+ public void testDetectStopsWithTripCut() throws Exception {
- Collection<Position> data = Arrays.asList(
+ var data = Arrays.asList(
position("2016-01-01 00:00:00.000", 0, 0),
position("2016-01-01 00:01:00.000", 0, 0),
position("2016-01-01 00:02:00.000", 0, 0),
position("2016-01-01 00:03:00.000", 0, 0),
position("2016-01-01 00:04:00.000", 1, 0),
position("2016-01-01 00:05:00.000", 2, 0));
+ when(storage.getObjects(eq(Position.class), any())).thenReturn(data);
- TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01);
+ Device device = mockDevice(500, 300, 200, 900, false);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null);
- Collection<StopReport> result = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class);
+ var result = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class);
assertNotNull(result);
assertFalse(result.isEmpty());
- StopReport itemStop = result.iterator().next();
+ StopReportItem itemStop = result.iterator().next();
assertEquals(date("2016-01-01 00:00:00.000"), itemStop.getStartTime());
assertEquals(date("2016-01-01 00:04:00.000"), itemStop.getEndTime());
@@ -297,47 +339,51 @@ public class ReportUtilsTest extends BaseTest {
}
@Test
- public void testDetectStopsStartedFromTrip() throws ParseException {
+ public void testDetectStopsStartedFromTrip() throws Exception {
- Collection<Position> data = Arrays.asList(
+ var data = Arrays.asList(
position("2016-01-01 00:00:00.000", 2, 0),
position("2016-01-01 00:01:00.000", 1, 0),
position("2016-01-01 00:02:00.000", 0, 0),
- position("2016-01-01 00:03:00.000", 0, 0),
- position("2016-01-01 00:04:00.000", 0, 0),
- position("2016-01-01 00:05:00.000", 0, 0));
+ position("2016-01-01 00:12:00.000", 0, 0),
+ position("2016-01-01 00:22:00.000", 0, 0),
+ position("2016-01-01 00:32:00.000", 0, 0));
+ when(storage.getObjects(eq(Position.class), any())).thenReturn(data);
- TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01);
+ Device device = mockDevice(500, 300, 200, 900, false);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null);
- Collection<StopReport> result = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class);
+ var result = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class);
assertNotNull(result);
assertFalse(result.isEmpty());
- StopReport itemStop = result.iterator().next();
+ StopReportItem itemStop = result.iterator().next();
assertEquals(date("2016-01-01 00:02:00.000"), itemStop.getStartTime());
- assertEquals(date("2016-01-01 00:05:00.000"), itemStop.getEndTime());
- assertEquals(180000, itemStop.getDuration());
+ assertEquals(date("2016-01-01 00:32:00.000"), itemStop.getEndTime());
+ assertEquals(1800000, itemStop.getDuration());
}
@Test
- public void testDetectStopsMoving() throws ParseException {
+ public void testDetectStopsMoving() throws Exception {
- Collection<Position> data = Arrays.asList(
+ var data = Arrays.asList(
position("2016-01-01 00:00:00.000", 5, 0),
position("2016-01-01 00:01:00.000", 5, 0),
position("2016-01-01 00:02:00.000", 3, 0),
position("2016-01-01 00:03:00.000", 5, 0),
position("2016-01-01 00:04:00.000", 5, 0),
position("2016-01-01 00:05:00.000", 5, 0));
+ when(storage.getObjects(eq(Position.class), any())).thenReturn(data);
- TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01);
+ Device device = mockDevice(500, 300, 200, 900, false);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null);
- Collection<StopReport> result = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class);
+ var result = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class);
assertNotNull(result);
assertTrue(result.isEmpty());
@@ -345,9 +391,9 @@ public class ReportUtilsTest extends BaseTest {
}
@Test
- public void testDetectTripAndStopByGap() throws ParseException {
+ public void testDetectTripAndStopByGap() throws Exception {
- Collection<Position> data = Arrays.asList(
+ var data = Arrays.asList(
position("2016-01-01 00:00:00.000", 7, 100),
position("2016-01-01 00:01:00.000", 7, 300),
position("2016-01-01 00:02:00.000", 5, 500),
@@ -356,16 +402,18 @@ public class ReportUtilsTest extends BaseTest {
position("2016-01-01 00:23:00.000", 2, 700),
position("2016-01-01 00:24:00.000", 5, 800),
position("2016-01-01 00:25:00.000", 5, 900));
+ when(storage.getObjects(eq(Position.class), any())).thenReturn(data);
- TripsConfig tripsConfig = new TripsConfig(500, 200000, 200000, 900000, false, false, 0.01);
+ Device device = mockDevice(500, 200, 200, 900, false);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class), mock(VelocityEngine.class), null);
- Collection<TripReport> trips = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, TripReport.class);
+ var trips = reportUtils.slowTripsAndStops(device, new Date(), new Date(), TripReportItem.class);
assertNotNull(trips);
assertFalse(trips.isEmpty());
- TripReport itemTrip = trips.iterator().next();
+ TripReportItem itemTrip = trips.iterator().next();
assertEquals(date("2016-01-01 00:00:00.000"), itemTrip.getStartTime());
assertEquals(date("2016-01-01 00:04:00.000"), itemTrip.getEndTime());
@@ -374,13 +422,12 @@ public class ReportUtilsTest extends BaseTest {
assertEquals(7, itemTrip.getMaxSpeed(), 0.01);
assertEquals(600, itemTrip.getDistance(), 0.01);
- Collection<StopReport> stops = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class);
+ var stops = reportUtils.slowTripsAndStops(device, new Date(), new Date(), StopReportItem.class);
assertNotNull(stops);
assertFalse(stops.isEmpty());
- StopReport itemStop = stops.iterator().next();
+ StopReportItem itemStop = stops.iterator().next();
assertEquals(date("2016-01-01 00:04:00.000"), itemStop.getStartTime());
assertEquals(date("2016-01-01 00:24:00.000"), itemStop.getEndTime());
diff --git a/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java b/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java
index dcac78f80..a59d1ce91 100644
--- a/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java
+++ b/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java
@@ -1,21 +1,22 @@
package org.traccar.speedlimit;
-import org.junit.Ignore;
-import org.junit.Test;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
+import jakarta.ws.rs.client.Client;
+import jakarta.ws.rs.client.ClientBuilder;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
public class OverpassSpeedLimitProviderTest {
- @Ignore
- @Test
- public void test() throws Exception {
- testLocationProvider();
- }
+ private final Client client = ClientBuilder.newClient();
- public void testLocationProvider() throws Exception {
- SpeedLimitProvider provider = new OverpassSpeedLimitProvider("http://8.8.8.8/api/interpreter");
+ @Disabled
+ @Test
+ public void testOverpass() throws Exception {
+ SpeedLimitProvider provider = new OverpassSpeedLimitProvider(client, "http://8.8.8.8/api/interpreter");
provider.getSpeedLimit(34.74767, -82.48098, new SpeedLimitProvider.SpeedLimitProviderCallback() {
@Override
diff --git a/src/test/java/org/traccar/web/WebServerTest.java b/src/test/java/org/traccar/web/WebServerTest.java
index ba4124e44..694dab18a 100644
--- a/src/test/java/org/traccar/web/WebServerTest.java
+++ b/src/test/java/org/traccar/web/WebServerTest.java
@@ -1,6 +1,6 @@
package org.traccar.web;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import javax.naming.Context;
import javax.naming.InitialContext;
diff --git a/swagger.json b/swagger.json
index ac0d73d5b..ccd26d4e8 100644
--- a/swagger.json
+++ b/swagger.json
@@ -2,7 +2,7 @@
"openapi": "3.0.1",
"info": {
"title": "Traccar",
- "version": "4.15",
+ "version": "5.8",
"description": "Traccar GPS tracking server API documentation. To use the API you need to have a server instance. For testing purposes you can use one of free [demo servers](https://www.traccar.org/demo-server/). For production use you can install your own server or get a [subscription service](https://www.traccar.org/product/tracking-server/).",
"contact": {
"name": "Traccar Support",
@@ -28,6 +28,10 @@
"description": "Demo Server 3"
},
{
+ "url": "https://demo4.traccar.org/api",
+ "description": "Demo Server 4"
+ },
+ {
"url": "https://server.traccar.org/api",
"description": "Subscription Server"
},
@@ -760,15 +764,9 @@
"required": true
},
"responses": {
- "200": {
- "description": "OK",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Permission"
- }
- }
- }
+ "204": {
+ "description": "No Content",
+ "content": {}
},
"400": {
"description": "No permission",
@@ -875,6 +873,54 @@
}
}
}
+ },
+ "delete": {
+ "summary": "Deletes all the Positions of a device in the time span specified",
+ "description": "",
+ "tags": [
+ "Positions"
+ ],
+ "parameters": [
+ {
+ "name": "deviceId",
+ "in": "query",
+ "description": "",
+ "schema": {
+ "type": "integer"
+ },
+ "required": true
+ },
+ {
+ "name": "from",
+ "in": "query",
+ "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`",
+ "schema": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "required": true
+ },
+ {
+ "name": "to",
+ "in": "query",
+ "description": "in IS0 8601 format. eg. `1963-11-22T18:30:00Z`",
+ "schema": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "required": true
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content",
+ "content": {}
+ },
+ "400": {
+ "description": "Bad Request",
+ "content": {}
+ }
+ }
}
},
"/server": {
@@ -1015,6 +1061,42 @@
}
}
},
+ "/session/openid/auth": {
+ "get": {
+ "summary": "Fetch Session information",
+ "tags": [
+ "Session"
+ ],
+ "parameters": [
+ {
+ }
+ ],
+ "responses": {
+ "303": {
+ "description": "Redirect to OpenID Connect identity provider",
+ "content": { }
+ }
+ }
+ }
+ },
+ "/session/openid/callback": {
+ "get": {
+ "summary": "OpenID Callback",
+ "tags": [
+ "Session"
+ ],
+ "parameters": [
+ {
+ }
+ ],
+ "responses": {
+ "303": {
+ "description": "Successful authentication, redirect to homepage",
+ "content": { }
+ }
+ }
+ }
+ },
"/users": {
"get": {
"summary": "Fetch a list of Users",
@@ -2643,6 +2725,12 @@
"type": "object",
"properties": {}
},
+ "geofenceIds": {
+ "type": "array",
+ "items": {
+ "type": "integer"
+ }
+ },
"attributes": {
"type": "object",
"properties": {}
@@ -2711,10 +2799,10 @@
"limitCommands": {
"type": "boolean"
},
- "poiLayer": {
- "type": "string"
+ "fixedEmail": {
+ "type": "boolean"
},
- "token": {
+ "poiLayer": {
"type": "string"
},
"attributes": {
@@ -2774,6 +2862,12 @@
"coordinateFormat": {
"type": "string"
},
+ "openIdEnabled": {
+ "type": "boolean"
+ },
+ "openIdForce": {
+ "type": "boolean"
+ },
"attributes": {
"type": "object",
"properties": {}
@@ -2842,12 +2936,6 @@
"category": {
"type": "string"
},
- "geofenceIds": {
- "type": "array",
- "items": {
- "type": "integer"
- }
- },
"attributes": {
"type": "object",
"properties": {}
@@ -2877,39 +2965,43 @@
"properties": {
"userId": {
"type": "integer",
- "description": "User Id, can be only first parameter"
+ "description": "User id, can be only first parameter"
},
"deviceId": {
"type": "integer",
- "description": "Device Id, can be first parameter or second only in combination with userId"
+ "description": "Device id, can be first parameter or second only in combination with userId"
},
"groupId": {
"type": "integer",
- "description": "Group Id, can be first parameter or second only in combination with userId"
+ "description": "Group id, can be first parameter or second only in combination with userId"
},
"geofenceId": {
"type": "integer",
- "description": "Geofence Id, can be second parameter only"
+ "description": "Geofence id, can be second parameter only"
},
"notificationId": {
"type": "integer",
- "description": "Notification Id, can be second parameter only"
+ "description": "Notification id, can be second parameter only"
},
"calendarId": {
"type": "integer",
- "description": "Calendar Id, can be second parameter only and only in combination with userId"
+ "description": "Calendar id, can be second parameter only and only in combination with userId"
},
"attributeId": {
"type": "integer",
- "description": "Computed Attribute Id, can be second parameter only"
+ "description": "Computed attribute id, can be second parameter only"
},
"driverId": {
"type": "integer",
- "description": "Driver Id, can be second parameter only"
+ "description": "Driver id, can be second parameter only"
},
"managedUserId": {
"type": "integer",
- "description": "User Id, can be second parameter only and only in combination with userId"
+ "description": "User id, can be second parameter only and only in combination with userId"
+ },
+ "commandId": {
+ "type": "integer",
+ "description": "Saved command id, can be second parameter only"
}
},
"description": "This is a permission map that contain two object indexes. It is used to link/unlink objects. Order is important. Example: { deviceId:8, geofenceId: 16 }"
@@ -3486,4 +3578,4 @@
}
}
}
-} \ No newline at end of file
+}
diff --git a/templates/export/events.xlsx b/templates/export/events.xlsx
index a6366750c..d0120ab8e 100644
--- a/templates/export/events.xlsx
+++ b/templates/export/events.xlsx
Binary files differ
diff --git a/templates/full/alarm.vm b/templates/full/alarm.vm
index 8eac3930a..fb596ecde 100644
--- a/templates/full/alarm.vm
+++ b/templates/full/alarm.vm
@@ -1,10 +1,90 @@
#set($subject = "$device.name: alarm!")
+#set($alarmName = $position.getString("alarm"))
+#if( $alarmName == "general")
+ #set($alarmName = "General")
+#elseif($alarmName == "sos")
+ #set($alarmName = "SOS")
+#elseif($alarmName == "vibration")
+ #set($alarmName = "Vibration")
+#elseif($alarmName == "movement")
+ #set($alarmName = "Movement")
+#elseif($alarmName == "lowspeed")
+ #set($alarmName = "Low Speed")
+#elseif($alarmName == "overspeed")
+ #set($alarmName = "Overspeed")
+#elseif($alarmName == "fallDown")
+ #set($alarmName = "Fall Down")
+#elseif($alarmName == "lowPower")
+ #set($alarmName = "Low Power")
+#elseif($alarmName == "lowBattery")
+ #set($alarmName = "Low Battery")
+#elseif($alarmName == "fault")
+ #set($alarmName = "Fault")
+#elseif($alarmName == "powerOff")
+ #set($alarmName = "Power Off")
+#elseif($alarmName == "powerOn")
+ #set($alarmName = "Power On")
+#elseif($alarmName == "door")
+ #set($alarmName = "Door")
+#elseif($alarmName == "lock")
+ #set($alarmName = "Lock")
+#elseif($alarmName == "unlock")
+ #set($alarmName = "Unlock")
+#elseif($alarmName == "geofence")
+ #set($alarmName = "Geofence")
+#elseif($alarmName == "geofenceEnter")
+ #set($alarmName = "Geofence Enter")
+#elseif($alarmName == "geofenceExit")
+ #set($alarmName = "Geofence Exit")
+#elseif($alarmName == "gpsAntennaCut")
+ #set($alarmName = "GPS Antenna Cut")
+#elseif($alarmName == "accident")
+ #set($alarmName = "Accident")
+#elseif($alarmName == "tow")
+ #set($alarmName = "Tow")
+#elseif($alarmName == "idle")
+ #set($alarmName = "Idle")
+#elseif($alarmName == "highRpm")
+ #set($alarmName = "High RPM")
+#elseif($alarmName == "hardAcceleration")
+ #set($alarmName = "Hard Acceleration")
+#elseif($alarmName == "hardBraking")
+ #set($alarmName = "Hard Braking")
+#elseif($alarmName == "hardCornering")
+ #set($alarmName = "Hard Cornering")
+#elseif($alarmName == "laneChange")
+ #set($alarmName = "Lane Change")
+#elseif($alarmName == "fatigueDriving")
+ #set($alarmName = "Fatigue Driving")
+#elseif($alarmName == "powerCut")
+ #set($alarmName = "Power Cut")
+#elseif($alarmName == "powerRestored")
+ #set($alarmName = "Power Restored")
+#elseif($alarmName == "jamming")
+ #set($alarmName = "Jamming")
+#elseif($alarmName == "temperature")
+ #set($alarmName = "Temperature")
+#elseif($alarmName == "parking")
+ #set($alarmName = "Parking")
+#elseif($alarmName == "bonnet")
+ #set($alarmName = "Bonnet")
+#elseif($alarmName == "footBrake")
+ #set($alarmName = "Foot Brake")
+#elseif($alarmName == "fuelLeak")
+ #set($alarmName = "Fuel Leak")
+#elseif($alarmName == "tampering")
+ #set($alarmName = "Tampering")
+#elseif($alarmName == "removing")
+ #set($alarmName = "Removing")
+#end
<!DOCTYPE html>
<html>
<body>
Device: $device.name<br>
-Alarm: $position.getString("alarm")<br>
+Alarm: $alarmName<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
Point: <a href="$webUrl?eventId=$event.id">#{if}($position.address)$position.address#{else}$position.latitude&deg;, $position.longitude&deg;#{end}</a><br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/commandResult.vm b/templates/full/commandResult.vm
index c5ceffab0..c3b62edf5 100644
--- a/templates/full/commandResult.vm
+++ b/templates/full/commandResult.vm
@@ -5,6 +5,8 @@
Device: $device.name<br>
Result: $position.getString("result")<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
-Link: <a href="$webUrl?eventId=$event.id">$webUrl?eventId=$event.id</a>
+Link: <a href="$webUrl?eventId=$event.id">$webUrl?eventId=$event.id</a><br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/deviceFuelDrop.vm b/templates/full/deviceFuelDrop.vm
index a50e8ca38..3fb9aa63c 100644
--- a/templates/full/deviceFuelDrop.vm
+++ b/templates/full/deviceFuelDrop.vm
@@ -5,5 +5,7 @@
Device: $device.name<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
Point: <a href="$webUrl?eventId=$event.id">#{if}($position.address)$position.address#{else}$position.latitude&deg;, $position.longitude&deg;#{end}</a><br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/deviceFuelIncrease.vm b/templates/full/deviceFuelIncrease.vm
new file mode 100644
index 000000000..9d4474e1a
--- /dev/null
+++ b/templates/full/deviceFuelIncrease.vm
@@ -0,0 +1,11 @@
+#set($subject = "$device.name: fuel increase")
+<!DOCTYPE html>
+<html>
+<body>
+Device: $device.name<br>
+Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
+Point: <a href="$webUrl?eventId=$event.id">#{if}($position.address)$position.address#{else}$position.latitude&deg;, $position.longitude&deg;#{end}</a><br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
+</body>
+</html>
diff --git a/templates/full/deviceInactive.vm b/templates/full/deviceInactive.vm
index 51aead653..01fa319b5 100644
--- a/templates/full/deviceInactive.vm
+++ b/templates/full/deviceInactive.vm
@@ -7,6 +7,8 @@
Device: $device.name<br>
Inactive<br>
Last Update: $dateTool.format("YYYY-MM-dd HH:mm:ss", $lastUpdate, $locale, $timezone)<br>
-Link: <a href="$webUrl?eventId=$event.id">$webUrl?eventId=$event.id</a>
+Link: <a href="$webUrl?eventId=$event.id">$webUrl?eventId=$event.id</a><br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/deviceMoving.vm b/templates/full/deviceMoving.vm
index 37f3c2a93..e3941b324 100644
--- a/templates/full/deviceMoving.vm
+++ b/templates/full/deviceMoving.vm
@@ -6,5 +6,7 @@ Device: $device.name<br>
Moving<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
Point: <a href="$webUrl?eventId=$event.id">#{if}($position.address)$position.address#{else}$position.latitude&deg;, $position.longitude&deg;#{end}</a><br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/deviceOffline.vm b/templates/full/deviceOffline.vm
index c832ee553..6d2122624 100644
--- a/templates/full/deviceOffline.vm
+++ b/templates/full/deviceOffline.vm
@@ -5,6 +5,7 @@
Device: $device.name<br>
Offline<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
-Link: <a href="$webUrl?eventId=$event.id">$webUrl?eventId=$event.id</a>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/deviceOnline.vm b/templates/full/deviceOnline.vm
index fd17edef0..02260c4fb 100644
--- a/templates/full/deviceOnline.vm
+++ b/templates/full/deviceOnline.vm
@@ -5,6 +5,7 @@
Device: $device.name<br>
Online<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
-Link: <a href="$webUrl?eventId=$event.id">$webUrl?eventId=$event.id</a>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/deviceOverspeed.vm b/templates/full/deviceOverspeed.vm
index f796881a0..5f38b3f88 100644
--- a/templates/full/deviceOverspeed.vm
+++ b/templates/full/deviceOverspeed.vm
@@ -15,5 +15,7 @@ Device: $device.name<br>
Exceeds the speed: $speedString#{if}($geofence) in $geofence.name#{else}#{end}<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
Point: <a href="$webUrl?eventId=$event.id">#{if}($position.address)$position.address#{else}$position.latitude&deg;, $position.longitude&deg;#{end}</a><br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/deviceStopped.vm b/templates/full/deviceStopped.vm
index 9e1e47d12..e3246b277 100644
--- a/templates/full/deviceStopped.vm
+++ b/templates/full/deviceStopped.vm
@@ -6,5 +6,7 @@ Device: $device.name<br>
Stopped<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
Point: <a href="$webUrl?eventId=$event.id">#{if}($position.address)$position.address#{else}$position.latitude&deg;, $position.longitude&deg;#{end}</a><br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/deviceUnknown.vm b/templates/full/deviceUnknown.vm
index 34b3a7795..e99981069 100644
--- a/templates/full/deviceUnknown.vm
+++ b/templates/full/deviceUnknown.vm
@@ -5,6 +5,7 @@
Device: $device.name<br>
Status is unknown<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
-Link: <a href="$webUrl?eventId=$event.id">$webUrl?eventId=$event.id</a>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/driverChanged.vm b/templates/full/driverChanged.vm
index e370d3eea..f9b6d0ae2 100644
--- a/templates/full/driverChanged.vm
+++ b/templates/full/driverChanged.vm
@@ -5,6 +5,8 @@
Device: $device.name<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
Point: <a href="$webUrl?eventId=$event.id">#{if}($position.address)$position.address#{else}$position.latitude&deg;, $position.longitude&deg;#{end}</a><br>
-Driver: #{if}($driver)$driver.name#{else}$event.getString("driverUniqueId")#{end}
+Driver: #{if}($driver)$driver.name#{else}$event.getString("driverUniqueId")#{end}<br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/geofenceEnter.vm b/templates/full/geofenceEnter.vm
index 9e00cb388..5ae14a8d3 100644
--- a/templates/full/geofenceEnter.vm
+++ b/templates/full/geofenceEnter.vm
@@ -6,5 +6,7 @@ Device: $device.name<br>
Has entered geofence: $geofence.name<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
Point: <a href="$webUrl?eventId=$event.id">#{if}($position.address)$position.address#{else}$position.latitude&deg;, $position.longitude&deg;#{end}</a><br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/geofenceExit.vm b/templates/full/geofenceExit.vm
index c3a300f37..08887a93a 100644
--- a/templates/full/geofenceExit.vm
+++ b/templates/full/geofenceExit.vm
@@ -6,5 +6,7 @@ Device: $device.name<br>
Has exited geofence: $geofence.name<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
Point: <a href="$webUrl?eventId=$event.id">#{if}($position.address)$position.address#{else}$position.latitude&deg;, $position.longitude&deg;#{end}</a><br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/ignitionOff.vm b/templates/full/ignitionOff.vm
index 8a546ed29..a43e4aabb 100644
--- a/templates/full/ignitionOff.vm
+++ b/templates/full/ignitionOff.vm
@@ -6,5 +6,7 @@ Device: $device.name<br>
Ignition OFF<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
Point: <a href="$webUrl?eventId=$event.id">#{if}($position.address)$position.address#{else}$position.latitude&deg;, $position.longitude&deg;#{end}</a><br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/ignitionOn.vm b/templates/full/ignitionOn.vm
index 9ae9a63e7..1ba9ef030 100644
--- a/templates/full/ignitionOn.vm
+++ b/templates/full/ignitionOn.vm
@@ -6,5 +6,7 @@ Device: $device.name<br>
Ignition ON<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
Point: <a href="$webUrl?eventId=$event.id">#{if}($position.address)$position.address#{else}$position.latitude&deg;, $position.longitude&deg;#{end}</a><br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/maintenance.vm b/templates/full/maintenance.vm
index 612a675f8..39ccb21bc 100644
--- a/templates/full/maintenance.vm
+++ b/templates/full/maintenance.vm
@@ -6,5 +6,7 @@ Device: $device.name<br>
Maintenance is required: $maintenance.name<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
Point: <a href="$webUrl?eventId=$event.id">#{if}($position.address)$position.address#{else}$position.latitude&deg;, $position.longitude&deg;#{end}</a><br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/full/media.vm b/templates/full/media.vm
new file mode 100644
index 000000000..1c94265fb
--- /dev/null
+++ b/templates/full/media.vm
@@ -0,0 +1,13 @@
+#set($subject = "$device.name: media file received")
+<!DOCTYPE html>
+<html>
+<body>
+Device: $device.name<br>
+Type: $event.getString("media")<br>
+File: <a href="$webUrl/api/media/$device.uniqueId/$event.getString("file")">$event.getString("file")</a><br>
+Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
+Link: <a href="$webUrl?eventId=$event.id">$webUrl?eventId=$event.id</a><br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
+</body>
+</html>
diff --git a/templates/full/passwordReset.vm b/templates/full/passwordReset.vm
index fe692ba1d..d380790dc 100644
--- a/templates/full/passwordReset.vm
+++ b/templates/full/passwordReset.vm
@@ -3,6 +3,6 @@
<html>
<body>
To reset password please click on the following link:<br>
-<a href="$webUrl?passwordReset=$token">$webUrl?passwordReset=$token</a><br>
+<a href="$webUrl/reset-password?passwordReset=$token">$webUrl/reset-password?passwordReset=$token</a><br>
</body>
</html>
diff --git a/templates/full/test.vm b/templates/full/test.vm
index 93cbdc549..41e2f3ebd 100644
--- a/templates/full/test.vm
+++ b/templates/full/test.vm
@@ -4,4 +4,4 @@
<body>
Test message
</body>
-</html>
+</html>
diff --git a/templates/full/textMessage.vm b/templates/full/textMessage.vm
index a20dddbe0..fb20275e3 100644
--- a/templates/full/textMessage.vm
+++ b/templates/full/textMessage.vm
@@ -3,7 +3,9 @@
<html>
<body>
Device: $device.name<br>
-Message: $event.getString("message")<br>
+Message: $event.getString("message")<br>
Time: $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)<br>
+<br>
+<a href="$webUrl/settings/notifications?token=$token">Unsubscribe</a>
</body>
-</html>
+</html>
diff --git a/templates/short/alarm.vm b/templates/short/alarm.vm
index 15970dab8..effcb8f15 100644
--- a/templates/short/alarm.vm
+++ b/templates/short/alarm.vm
@@ -1,2 +1,80 @@
#set($subject = "$device.name: alarm!")
-$device.name alarm: $position.getString("alarm") at $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)
+#set($alarmName = $position.getString("alarm"))
+#if( $alarmName == "general")
+ #set($alarmName = "General")
+#elseif($alarmName == "sos")
+ #set($alarmName = "SOS")
+#elseif($alarmName == "vibration")
+ #set($alarmName = "Vibration")
+#elseif($alarmName == "movement")
+ #set($alarmName = "Movement")
+#elseif($alarmName == "lowspeed")
+ #set($alarmName = "Low Speed")
+#elseif($alarmName == "overspeed")
+ #set($alarmName = "Overspeed")
+#elseif($alarmName == "fallDown")
+ #set($alarmName = "Fall Down")
+#elseif($alarmName == "lowPower")
+ #set($alarmName = "Low Power")
+#elseif($alarmName == "lowBattery")
+ #set($alarmName = "Low Battery")
+#elseif($alarmName == "fault")
+ #set($alarmName = "Fault")
+#elseif($alarmName == "powerOff")
+ #set($alarmName = "Power Off")
+#elseif($alarmName == "powerOn")
+ #set($alarmName = "Power On")
+#elseif($alarmName == "door")
+ #set($alarmName = "Door")
+#elseif($alarmName == "lock")
+ #set($alarmName = "Lock")
+#elseif($alarmName == "unlock")
+ #set($alarmName = "Unlock")
+#elseif($alarmName == "geofence")
+ #set($alarmName = "Geofence")
+#elseif($alarmName == "geofenceEnter")
+ #set($alarmName = "Geofence Enter")
+#elseif($alarmName == "geofenceExit")
+ #set($alarmName = "Geofence Exit")
+#elseif($alarmName == "gpsAntennaCut")
+ #set($alarmName = "GPS Antenna Cut")
+#elseif($alarmName == "accident")
+ #set($alarmName = "Accident")
+#elseif($alarmName == "tow")
+ #set($alarmName = "Tow")
+#elseif($alarmName == "idle")
+ #set($alarmName = "Idle")
+#elseif($alarmName == "highRpm")
+ #set($alarmName = "High RPM")
+#elseif($alarmName == "hardAcceleration")
+ #set($alarmName = "Hard Acceleration")
+#elseif($alarmName == "hardBraking")
+ #set($alarmName = "Hard Braking")
+#elseif($alarmName == "hardCornering")
+ #set($alarmName = "Hard Cornering")
+#elseif($alarmName == "laneChange")
+ #set($alarmName = "Lane Change")
+#elseif($alarmName == "fatigueDriving")
+ #set($alarmName = "Fatigue Driving")
+#elseif($alarmName == "powerCut")
+ #set($alarmName = "Power Cut")
+#elseif($alarmName == "powerRestored")
+ #set($alarmName = "Power Restored")
+#elseif($alarmName == "jamming")
+ #set($alarmName = "Jamming")
+#elseif($alarmName == "temperature")
+ #set($alarmName = "Temperature")
+#elseif($alarmName == "parking")
+ #set($alarmName = "Parking")
+#elseif($alarmName == "bonnet")
+ #set($alarmName = "Bonnet")
+#elseif($alarmName == "footBrake")
+ #set($alarmName = "Foot Brake")
+#elseif($alarmName == "fuelLeak")
+ #set($alarmName = "Fuel Leak")
+#elseif($alarmName == "tampering")
+ #set($alarmName = "Tampering")
+#elseif($alarmName == "removing")
+ #set($alarmName = "Removing")
+#end
+$device.name alarm: $alarmName at $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)
diff --git a/templates/short/deviceFuelIncrease.vm b/templates/short/deviceFuelIncrease.vm
new file mode 100644
index 000000000..6a11418b1
--- /dev/null
+++ b/templates/short/deviceFuelIncrease.vm
@@ -0,0 +1,2 @@
+#set($subject = "$device.name: fuel increase")
+$device.name fuel increase at $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)
diff --git a/templates/short/media.vm b/templates/short/media.vm
new file mode 100644
index 000000000..783636f3f
--- /dev/null
+++ b/templates/short/media.vm
@@ -0,0 +1,2 @@
+#set($subject = "$device.name: media file received")
+$device.name $event.getString("media") received: $event.getString("file") at $dateTool.format("YYYY-MM-dd HH:mm:ss", $event.eventTime, $locale, $timezone)
diff --git a/tools/gen_config_doc.py b/tools/config-doc.py
index 98266386e..c55b2b5ef 100644..100755
--- a/tools/gen_config_doc.py
+++ b/tools/config-doc.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
import re
import os
@@ -22,6 +22,7 @@ def get_config_keys():
desc_re = re.compile(r"(/\*\*\n|\s+\*/|\s+\*)")
key_match_re = re.compile(r"\(\n(.+)\);", re.DOTALL)
key_split_re = re.compile(r",\s+", re.DOTALL)
+ types_match_re = re.compile(r"List\.of\(([^)]+)\)", re.DOTALL)
keys = []
with open(_KEYS_FILE, "r") as f:
@@ -34,16 +35,18 @@ def get_config_keys():
if key_match:
terms = [x.strip() for x in key_split_re.split(key_match.group(1))]
key = terms[0].replace('"', "")
+ key = "[protocol]" + key if key.startswith('.') else key
description = [
x.strip().replace("\n", "")
for x in desc_re.sub("\n", i[0]).strip().split("\n\n")
]
- if len(terms) == 3:
- description.append(f"Default: {terms[2]}")
+ types_match = types_match_re.search(i[1])
+ types = map(lambda x: x[8:].lower(), types_match[1].split(", "))
keys.append(
{
"key": key,
"description": description,
+ "types": types,
}
)
except IndexError:
@@ -60,7 +63,7 @@ def get_html():
f""" <div class="card mt-3">
<div class="card-body">
<h5 class="card-title">
- {x["key"]} <span class="badge badge-dark">config</span>
+ {x["key"]}
</h5>
<p class="card-text">
{"<br /> ".join(x["description"])}
@@ -77,7 +80,7 @@ def get_pug():
[
f""" div(class='card mt-3')
div(class='card-body')
- h5(class='card-title') {x["key"]} #[span(class='badge badge-dark') config]
+ h5(class='card-title') {x["key"]} {" ".join(map("#[span(class='badge badge-dark') {:}]".format, x["types"]))}
p(class='card-text') {"#[br] ".join(x["description"])}"""
for x in get_config_keys()
]
@@ -99,4 +102,4 @@ if __name__ == "__main__":
return get_pug()
- print(get_output()) \ No newline at end of file
+ print(get_output())
diff --git a/tools/recover.py b/tools/recover.py
index 01e01f92e..32e3f8721 100755
--- a/tools/recover.py
+++ b/tools/recover.py
@@ -1,35 +1,52 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
import sys
import re
+import os
+import xml.etree.ElementTree
import socket
import binascii
+import time
if len(sys.argv) < 2:
sys.exit("log file is not provided")
path = sys.argv[1]
-p = re.compile(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} DEBUG: \[([0-9a-fA-F]{8}): (\d+) < [\d.]+] HEX: ([0-9a-fA-F]+)")
+p = re.compile(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} INFO: \[([TU][0-9a-fA-F]{8}): (\S+) < [\d.]+] ([0-9a-fA-F]+)")
-ports = {}
+def load_ports():
+ ports = {}
+ dir = os.path.dirname(os.path.abspath(__file__))
+ root = xml.etree.ElementTree.parse(dir + '/../setup/default.xml').getroot()
+ for entry in root.findall('entry'):
+ key = entry.attrib['key']
+ if key.endswith('.port'):
+ ports[key[:-5]] = int(entry.text)
+ return ports
+
+ports = load_ports()
+protocols = {}
messages = {}
for line in open(path):
- if "HEX:" in line:
- m = p.match(line)
- if m:
- session = m.group(1)
- port = m.group(2)
- message = m.group(3)
- ports[session] = port
- if session not in messages:
- messages[session] = []
- messages[session].append(message)
-
-for session in ports:
- port = ports[session]
+ print(line)
+ m = p.match(line)
+ if m:
+ session = m.group(1)
+ protocol = m.group(2)
+ message = m.group(3)
+ protocols[session] = protocol
+ if session not in messages:
+ messages[session] = []
+ messages[session].append(message)
+
+print('Total: %d' % len(messages))
+
+for session in protocols:
+ port = ports[protocols[session]]
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", int(port)))
for message in messages[session]:
s.send(binascii.unhexlify(message))
+ time.sleep(0.1)
s.close()
diff --git a/tools/test-commands.py b/tools/test-commands.py
index 040efb177..7efd963b4 100755
--- a/tools/test-commands.py
+++ b/tools/test-commands.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
import socket
import binascii
@@ -6,9 +6,9 @@ import binascii
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", 5001))
#s.send(binascii.unhexlify('68680f0504035889905831401700df1a00000d0a'))
-s.send("imei:123456789012345,tracker,151030080103,,F,000101.000,A,5443.3834,N,02512.9071,E,0.00,0;")
+s.send(b"imei:123456789012345,tracker,151030080103,,F,000101.000,A,5443.3834,N,02512.9071,E,0.00,0;")
while True:
- print s.recv(1024)
+ print(s.recv(1024))
s.close()
diff --git a/tools/test-generator.py b/tools/test-generator.py
index b8a06ac32..ed135b4aa 100755
--- a/tools/test-generator.py
+++ b/tools/test-generator.py
@@ -1,9 +1,9 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
import sys
import math
import urllib
-import httplib
+import http.client as httplib
import time
import random
@@ -35,8 +35,8 @@ for i in range(0, len(waypoints)):
lon = lon1 + (lon2 - lon1) * j / count
points.append((lat, lon))
-def send(conn, lat, lon, course, speed, battery, alarm, ignition, accuracy, rpm, fuel, driverUniqueId):
- params = (('id', id), ('timestamp', int(time.time())), ('lat', lat), ('lon', lon), ('bearing', course), ('speed', speed), ('batt', battery))
+def send(conn, lat, lon, altitude, course, speed, battery, alarm, ignition, accuracy, rpm, fuel, driverUniqueId):
+ params = (('id', id), ('timestamp', int(time.time())), ('lat', lat), ('lon', lon), ('altitude', altitude), ('bearing', course), ('speed', speed), ('batt', battery))
if alarm:
params = params + (('alarm', 'sos'),)
if ignition:
@@ -51,7 +51,7 @@ def send(conn, lat, lon, course, speed, battery, alarm, ignition, accuracy, rpm,
params = params + (('fuel', fuel),)
if driverUniqueId:
params = params + (('driverUniqueId', driverUniqueId),)
- conn.request('GET', '?' + urllib.urlencode(params))
+ conn.request('GET', '?' + urllib.parse.urlencode(params))
conn.getresponse().read()
def course(lat1, lon1, lat2, lon2):
@@ -70,14 +70,15 @@ conn = httplib.HTTPConnection(server)
while True:
(lat1, lon1) = points[index % len(points)]
(lat2, lon2) = points[(index + 1) % len(points)]
+ altitude = 50
speed = device_speed if (index % len(points)) != 0 else 0
alarm = (index % 10) == 0
battery = random.randint(0, 100)
- ignition = (index % len(points)) != 0
+ ignition = (index / 10 % 2) != 0
accuracy = 100 if (index % 10) == 0 else 0
rpm = random.randint(500, 4000)
fuel = random.randint(0, 80)
driverUniqueId = driver_id if (index % len(points)) == 0 else False
- send(conn, lat1, lon1, course(lat1, lon1, lat2, lon2), speed, battery, alarm, ignition, accuracy, rpm, fuel, driverUniqueId)
+ send(conn, lat1, lon1, altitude, course(lat1, lon1, lat2, lon2), speed, battery, alarm, ignition, accuracy, rpm, fuel, driverUniqueId)
time.sleep(period)
index += 1
diff --git a/tools/test-integration.py b/tools/test-integration.py
index 6251b0d97..204fecb70 100755
--- a/tools/test-integration.py
+++ b/tools/test-integration.py
@@ -1,10 +1,10 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
import sys
import os
import xml.etree.ElementTree
import urllib
-import urllib2
+import urllib.request as urllib2
import json
import socket
import time
@@ -18,10 +18,9 @@ messages = {
't55' : '$PGID,123456789012345*0F\r\n$GPRMC,120500.000,A,6000.0000,N,13000.0000,E,0.00,0.00,010112,,*33\r\n',
'xexun' : '111111120009,+436763737552,GPRMC,120600.000,A,6000.0000,N,13000.0000,E,0.00,0.00,010112,,,A*68,F,, imei:123456789012345,04,481.2,F:4.15V,0,139,2689,232,03,2725,0576\n',
'totem' : '$$B3123456789012345|AA$GPRMC,120700.000,A,6000.0000,N,13000.0000,E,0.00,,010112,,,A*74|01.8|01.0|01.5|000000000000|20120403234603|14251914|00000000|0012D888|0000|0.0000|3674|940B\r\n',
- 'meiligao' : '$$\x00\x60\x12\x34\x56\xFF\xFF\xFF\xFF\x99\x55120900.000,A,6000.0000,N,13000.0000,E,0.00,,010112,,*1C|11.5|194|0000|0000,0000\x69\x62\x0D\x0A',
'suntech' : 'SA200STT;123456;042;20120101;12:11:00;16d41;-15.618767;-056.083214;000.011;000.00;11;1;41557;12.21;000000;1;3205\r',
'h02' : '*HQ,123456789012345,V1,121300,A,6000.0000,N,13000.0000,E,0.00,0.00,010112,ffffffff,000000,000000,000000,000000#',
- 'jt600' : '$\x00\x00\x12\x34\x56\x11\x00\x1B\x01\x01\x12\x12\x14\x00\x60\x00\x00\x00\x13\x00\x00\x00\x0F\x00\x00\x07\x50\x00\x00\x00\x2B\x91\x04\x4D\x1F\xA1',
+ 'jt600' : '(1234567890,P45,290322,132412,25.28217,S,57.54683,W,A,0,0,5,0,0000000000,0,0,9,0)',
'v680' : '#123456789012345#1000#0#1000#AUT#1#66830FFB#13000.0000,E,6000.0000,N,001.41,259#010112#121600##',
'pt502' : '$POS,123456,121700.000,A,6000.0000,N,13000.0000,E,0.0,0.0,010112,,,A/00000,00000/0/23895000//\r\n',
'tr20' : '%%123456789012345,A,120101121800,N6000.0000E13000.0000,0,000,0,01034802,150,[Message]\r\n',
@@ -89,7 +88,45 @@ messages = {
'siwi' : '$SIWI,1234,1320,A,0,,1,1,0,0,876578,43,10,A,19.0123456,72.65347,45,0,055929,071107,22,5,1,0,3700,1210,0,2500,1230,321,0,1.1,4.0,1!\r\n',
'starlink' : '$SLU123456,06,622,170329035057,01,170329035057,+3158.0018,+03446.6968,004.9,007,000099,1,1,0,0,0,0,0,0,,,14.176,03.826,,1,1,1,4*B0\r\n',
'alematics' : '$T,50,592,123456789012345,20170515062915,20170515062915,25.035005,121.561555,0,31,89,3.7,5,1,0,0.000,12.752,1629,38,12752,4203,6\r\n',
- 'vtfms' : '(123456789012345,00I76,00,000,,,,,A,133755,210617,10.57354,077.24912,SW,000,00598,00000,K,0017368,1,12.7,,,0.000,,,0,0,0,0,1,1,0,,)074'
+ 'vtfms' : '(123456789012345,00I76,00,000,,,,,A,133755,210617,10.57354,077.24912,SW,000,00598,00000,K,0017368,1,12.7,,,0.000,,,0,0,0,0,1,1,0,,)074',
+ 'esky': 'ET;0;123456789012345;R;6+190317162511+41.32536+19.83144+0.14+0+0x0+0+18460312+0+1233+192',
+ 'genx': '123456789012345,08/31/2017 17:24:13,45.47275,-73.65491,5,19,117,1.14,147,ON,1462,0,6,N,0,0.000,-95.0,-1.0,0,0.0000,0.0000,0.000,0,0.00,0.00,0.00,NA,U,UUU,0,-95.0,U\r\n',
+ 'dway': 'AA55,115,1234,1,171024,195059,28.0153,-82.4761,3, 1.0,319,1000,0000,00000,4244,0,0,0,D\r\n',
+ 'oko': '{123456789012345,090745,A,4944.302,N,02353.366,E,0.0,225,251120,7,0.27,F9,11.3,1}',
+ 'ivt401': '(TLN,123456789012345,250118,063827,+18.598098,+73.806518,0,79,0,1,1,5,1200,0,0.0,11.50,4.00,36,0,0,1.00,0,0,12702,202,0);',
+ 't57': '*T57#F1#1234567890#301117#000843#2234.1303#N#08826.1714#E#+0.242,+0.109,-0.789#0.000#6.20000#A2#4.2#',
+ 'm2c': '[#M2C,2020,P1.B1.H1.F1.R1,101,123456789012345,2,L,1,100,170704,074933,28.647556,77.192940,900,194,0.0,0,0,0,255,11942,0,0,0,0,0,0,0,0,30068,5051,0,0,1*8159\r\n]',
+ 'cautela': '20,123456789012,14,02,18,16.816667,96.166667,1325,S,*2E\r\n',
+ 'pt60': '@B#@|01|001|123456789012345|9425010450971470|1|45|20181127122717|32.701093|35.570938|1|@R#@',
+ 'telemax': '%061234560128\r\nY000007C6999999067374074649003C00A7018074666F60D66818051304321900000000C5\r\n',
+ 'svias': '[7061,3041,57,1234567890,710,40618,141342,-93155840,-371754060,0,20469,0,16,1,0,0,11323,100,9,,32,4695]',
+ 'eseal': '##S,eSeal,123456,256,3.0.6,Normal,34,2017-08-31,08:14:40,15,A,25.708828N 100.372870W,10,0,Close,0.71,0:0:3:0,3.8,-73,E##\r\n',
+ 'avema': '1234567890,20190522093835,121.645898,25.062268,0,0,0,0,3,0.0,1,0.02,11.48,0,0,19,4,466-5,65534,56589841,0.01\r\n',
+ 'milesmate': 'ApiString={A:123456789012345,B:09.8,C:00.0,D:083506,E:2838.5529N,F:07717.8049E,G:000.00,H:170918,I:G,J:00004100,K:0000000A,L:1234,M:126.86}\r\n',
+ 'smartsole': '#GTXRP=123456789012345,8,180514200051,34.041981,-118.255806,60,1,1,7,1.80,180514200051,4.16,11$',
+ 'its': '$,EPB,SEM,123456789012345,NM,14072020112020,A,28.359959,N,076.927566,E,260.93,0.1,0.0,G,NA00000000,N.A0000000,*',
+ 'xrb28': '*SCOR,OM,123456789012345,D0,0,012102.00,A,0608.00062,S,10659.70331,E,12,0.69,151118,30.3,M,A#\r\n',
+ 'c2stek': 'PA$123456789012345$D#220222#135059#0#+37.98995#+23.85141#0.00#69.2#0.0#0000#000#8#00#sz-w1001#B2600$AP',
+ 'mictrack': 'MT;6;123456789012345;R0;10+190109091803+22.63827+114.02922+2.14+69+2+3744+113',
+ 'plugin': '$$STATUS123456,20190528143943,28.254086,-25.860665,0,0,0,-1,2,78,11395,0,0,0#',
+ 'racedynamics': '$GPRMC,12,260819,100708,123456789012345,\r\n$GPRMC,15,04,H,#,100632,A,1255.5106,N,07738.2954,E,001,260819,0887,06,1,00011,%,0000000000000000,000,000,0,0,1,0713,0,416,0,255,000,0,000,3258,000,000,00,0000,000,00000,0,F3VF01\r\n',
+ 's168': 'S168#123456789012345#0f12#0077#LOCA:G;CELL:1,1cc,2,2795,1435,64;GDATA:A,12,160412154800,22.564025,113.242329,5.5,152,900;ALERT:0000;STATUS:89,98;WAY:0$',
+ 'dingtek': '800001011e0692001a00000000016e008027c40000112345678901234581',
+ 'portman': '$PTMLA,123456789012345,A,200612153351,N2543.0681W10009.2974,0,190,NA,C9830000,NA,108,8,2.66,16,GNA\r\n',
+ 'futureway': '410000003F2000020,IMEI:123456789012345,battery level:6,network type:7,CSQ:236F42410000009BA00004GPS:V,200902093333,0.000000N,0.000000E,0.000,0.000\r\nWIFI:3,1|90-67-1C-F7-21-6C|52&2|80-89-17-C6-79-A0|54&3|40-F4-20-EF-DD-2A|58\r\nLBS:460,0,46475066,69\r\n6A42',
+ 'net': '@L03612345678901234512271020161807037078881037233751000000010F850036980A4000!',
+ 'mobilogix': '[2020-10-25 20:45:09,T9,1,V1.2.3,123456789012,59,10.50,701,-25.236860,-45.708530,0,314]',
+ 'swiftech': '@@123456789012345,,0,102040,1023.9670,N,07606.8160,E,2.26,151220,A,0127,1,1,03962,00000,#',
+ 'ennfu': 'Ennfu:123456789012345,041504.00,A,3154.86654,N,11849.08737,E,0.053,,080121,20,3.72,21.4,V0.01$',
+ 'startek': '&&o125,123456789012345,000,0,,210702235150,A,27.263505,153.037061,11,1.2,0,0,31,5125,505|1|7032|8C89802,20,0000002D,00,00,01E2|019DF0\r\n',
+ 'hoopo': '{ "deviceId": "123456789012345", "assetName": "123456789012345", "assetType": "test", "eventData": { "latitude": 31.97498, "longitude": 34.80802, "locationName": "", "accuracyLevel": "High", "eventType": "Arrival", "batteryLevel": 100, "receiveTime": "2021-09-20T18:52:32Z" }, "eventTime": "2021-09-20T08:52:02Z", "serverReportTime": "0001-01-01T00:00:00Z" }',
+ 'techtocruz': '$$A120,123456789012345,211005105836,A,FLEX,KCB 947C,000.0,0,-1.38047,S,36.93951,E,1648.4,243.140,21,28,12.1,3.7,0,1,0,0,0,*F6',
+ 'flexapi': '${"topic":"v1/123456789012345/motion/info","payload":{"motion.ts":1641885877,"motion.ax":0.006344,"motion.ay":0.289384,"motion.az":-0.939156,"motion.gx":0.420000,"motion.gy":0.420000,"motion.gz":-0.280000}}xx\r\n',
+ 'jido': '*123456789012345,03,130517,160435,1820.5845,N,07833.2478,E,1,58#',
+ 'armoli': '[M123456789012345210122125205N38.735641E035.4727751E003340000000C00000E9E07FF:106AG505283H60E];',
+ 'teratrack': '{"MDeviceID":"022043756090","DiviceType":"1","DataType":"1","DataLength":"69","DateTime":"2022-03-09 10:56:01","Latitude":"-6.846451","Longitude":"39.316324","LongitudeState":"1","LatitudeState":"0","Speed":"90","Mileage":"0","FenceAlarm":"0","AreaAlarmID":"0","LockCutOff":"0","SealTampered":"0","MessageAck":"1","LockRope":"1","LockStatus":"1","LockOpen":"0","PasswordError":"0","CardNo":"60000644","IllegalCard":"0","LowPower":"0","UnCoverBack":"0","CoverStatus":"1","LockStuck":"0","Power":"79","GSM":"16","IMEI":"123456789012345","Index":"20","Slave":[]}',
+ 'envotech': '$80SLM,02,F,123456,130410155921,431750216,000040,0000,,00000000,\'13041015592110476673N10111459E001281*2A#',
+ 'bstpl': 'BSTPL$1,123456789012345,V,200722,045113,00.000000,0,00.00000,0,0,0,000,00,0,17,1,1,0,0,00.01,0,04.19,15B_190821,8991000907387031196F,12.27#',
}
baseUrl = 'http://localhost:8082'
@@ -106,14 +143,14 @@ def load_ports():
if key.endswith('.port'):
ports[key[:-5]] = int(entry.text)
if debug:
- print '\nports: %s\n' % repr(ports)
+ print('\nports: {ports!r}\n')
return ports
def login():
request = urllib2.Request(baseUrl + '/api/session')
- response = urllib2.urlopen(request, urllib.urlencode(user))
+ response = urllib2.urlopen(request, urllib.parse.urlencode(user).encode())
if debug:
- print '\nlogin: %s\n' % repr(json.load(response))
+ print(f'\nlogin: {json.load(response)!r}\n')
return response.headers.get('Set-Cookie')
def remove_devices(cookie):
@@ -122,7 +159,7 @@ def remove_devices(cookie):
response = urllib2.urlopen(request)
data = json.load(response)
if debug:
- print '\ndevices: %s\n' % repr(data)
+ print(f'\ndevices: {data!r}\n')
for device in data:
request = urllib2.Request(baseUrl + '/api/devices/' + str(device['id']))
request.add_header('Cookie', cookie)
@@ -134,20 +171,20 @@ def add_device(cookie, unique_id):
request.add_header('Cookie', cookie)
request.add_header('Content-Type', 'application/json')
device = { 'name' : unique_id, 'uniqueId' : unique_id }
- response = urllib2.urlopen(request, json.dumps(device))
+ response = urllib2.urlopen(request, json.dumps(device).encode())
data = json.load(response)
return data['id']
def send_message(port, message):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', port))
- s.send(message)
- time.sleep(5)
+ s.send(message.encode('ascii'))
+ time.sleep(0.5)
s.close()
def get_protocols(cookie, device_id):
params = { 'deviceId' : device_id, 'from' : '2000-01-01T00:00:00.000Z', 'to' : '2050-01-01T00:00:00.000Z' }
- request = urllib2.Request(baseUrl + '/api/positions?' + urllib.urlencode(params))
+ request = urllib2.Request(baseUrl + '/api/positions?' + urllib.parse.urlencode(params))
request.add_header('Cookie', cookie)
request.add_header('Content-Type', 'application/json')
request.add_header('Accept', 'application/json')
@@ -174,24 +211,18 @@ if __name__ == "__main__":
all = set(ports.keys())
protocols = set(messages.keys())
- print 'Total: %d' % len(all)
- print 'Missing: %d' % len(all - protocols)
- print 'Covered: %d' % len(protocols)
-
- #if all - protocols:
- # print '\nMissing: %s\n' % repr(list((all - protocols)))
+ print(f'Total: {len(all)}')
+ print(f'Missing: {len(all - protocols)}')
+ print(f'Covered: {len(protocols)}')
for protocol in messages:
- thread = threading.Thread(target = send_message, args = (ports[protocol], messages[protocol]))
- thread.start()
-
- time.sleep(10)
+ send_message(ports[protocol], messages[protocol])
for device in devices:
protocols -= set(get_protocols(cookie, devices[device]))
- print 'Success: %d' % (len(messages) - len(protocols))
- print 'Failed: %d' % len(protocols)
+ print(f'Success: {len(messages) - len(protocols)}')
+ print(f'Failed:{len(protocols)}')
if protocols:
- print '\nFailed: %s' % repr(list(protocols))
+ print(f'\nFailed: {list(protocols)!r}')
diff --git a/tools/test-map.py b/tools/test-map.py
index c289df605..664917eff 100755
--- a/tools/test-map.py
+++ b/tools/test-map.py
@@ -1,8 +1,8 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
import urllib
-import urllib2
-import httplib
+import urllib.request as urllib2
+import http.client as httplib
import time
import random
import json
@@ -14,7 +14,7 @@ devices = 500
def login():
request = urllib2.Request(baseUrl + '/api/session')
- response = urllib2.urlopen(request, urllib.urlencode(user))
+ response = urllib2.urlopen(request, urllib.parse.urlencode(user).encode())
return response.headers.get('Set-Cookie')
def add_device(cookie, unique_id):
@@ -23,13 +23,13 @@ def add_device(cookie, unique_id):
request.add_header('Content-Type', 'application/json')
device = { 'name' : unique_id, 'uniqueId' : unique_id }
try:
- response = urllib2.urlopen(request, json.dumps(device))
+ response = urllib2.urlopen(request, json.dumps(device).encode())
except urllib2.HTTPError:
pass
def send_message(conn, device_id):
params = (('id', device_id), ('lat', random.uniform(59, 61)), ('lon', random.uniform(29, 31)))
- conn.request('GET', '?' + urllib.urlencode(params))
+ conn.request('GET', '?' + urllib.parse.urlencode(params))
conn.getresponse().read()
cookie = login()
@@ -38,6 +38,7 @@ conn = httplib.HTTPConnection(server)
for i in range(devices):
device_id = "{0:0>6}".format(i)
add_device(cookie, device_id)
+ send_message(conn, device_id)
while True:
device_id = "{0:0>6}".format(random.randint(0, devices))
diff --git a/tools/test-performance.py b/tools/test-performance.py
index ec31e9b86..a2dd6e66d 100755
--- a/tools/test-performance.py
+++ b/tools/test-performance.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python3
+#!/usr/bin/env python3
import asyncio
import random
diff --git a/tools/test-trips.py b/tools/test-trips.py
index a71357fdb..3c994fd83 100755
--- a/tools/test-trips.py
+++ b/tools/test-trips.py
@@ -1,7 +1,7 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
import urllib
-import httplib
+import http.client as httplib
import time
import datetime
@@ -25,7 +25,7 @@ points = [
def send(conn, time, lat, lon, speed):
params = (('id', id), ('timestamp', int(time)), ('lat', lat), ('lon', lon), ('speed', speed))
- conn.request('POST', '?' + urllib.urlencode(params))
+ conn.request('POST', '?' + urllib.parse.urlencode(params))
conn.getresponse().read()
conn = httplib.HTTPConnection(server)
diff --git a/traccar-web b/traccar-web
-Subproject 9e1c0b44189136ec6abf05720c698027a689fa0
+Subproject f8048106dacb36466ae221a8258da85f35db6e9