aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/gradle.yml12
-rw-r--r--.github/workflows/release.yml59
-rw-r--r--.gitignore1
-rw-r--r--build.gradle68
-rw-r--r--debug.xml8
-rw-r--r--gradle/checkstyle.xml8
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin58695 -> 59821 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties2
-rwxr-xr-xgradlew257
-rw-r--r--gradlew.bat25
-rw-r--r--schema/changelog-4.0-clean.xml8
-rw-r--r--schema/changelog-5.0.xml33
-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.xml17
-rw-r--r--schema/changelog-master.xml10
-rw-r--r--setup/default.xml49
-rw-r--r--setup/environment.sh27
-rwxr-xr-xsetup/package.sh29
-rw-r--r--setup/traccar.iss2
-rw-r--r--src/main/java/org/traccar/BasePipelineFactory.java45
-rw-r--r--src/main/java/org/traccar/BaseProtocol.java30
-rw-r--r--src/main/java/org/traccar/BaseProtocolDecoder.java177
-rw-r--r--src/main/java/org/traccar/BaseProtocolEncoder.java29
-rw-r--r--src/main/java/org/traccar/BaseProtocolPoller.java55
-rw-r--r--src/main/java/org/traccar/Context.java416
-rw-r--r--src/main/java/org/traccar/ExtendedObjectDecoder.java22
-rw-r--r--src/main/java/org/traccar/LifecycleObject.java21
-rw-r--r--src/main/java/org/traccar/Main.java55
-rw-r--r--src/main/java/org/traccar/MainEventHandler.java84
-rw-r--r--src/main/java/org/traccar/MainModule.java451
-rw-r--r--src/main/java/org/traccar/PositionForwardingHandler.java141
-rw-r--r--src/main/java/org/traccar/Protocol.java2
-rw-r--r--src/main/java/org/traccar/ServerManager.java97
-rw-r--r--src/main/java/org/traccar/TrackerClient.java125
-rw-r--r--src/main/java/org/traccar/TrackerConnector.java (renamed from src/main/java/org/traccar/database/ManagableObjects.java)15
-rw-r--r--src/main/java/org/traccar/TrackerServer.java75
-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.java35
-rw-r--r--src/main/java/org/traccar/api/BaseObjectResource.java185
-rw-r--r--src/main/java/org/traccar/api/BaseResource.java17
-rw-r--r--src/main/java/org/traccar/api/CorsResponseFilter.java16
-rw-r--r--src/main/java/org/traccar/api/ExtendedObjectResource.java57
-rw-r--r--src/main/java/org/traccar/api/MediaFilter.java53
-rw-r--r--src/main/java/org/traccar/api/SimpleObjectResource.java38
-rw-r--r--src/main/java/org/traccar/api/resource/AttributeResource.java69
-rw-r--r--src/main/java/org/traccar/api/resource/CommandResource.java122
-rw-r--r--src/main/java/org/traccar/api/resource/DeviceResource.java166
-rw-r--r--src/main/java/org/traccar/api/resource/EventResource.java28
-rw-r--r--src/main/java/org/traccar/api/resource/NotificationResource.java60
-rw-r--r--src/main/java/org/traccar/api/resource/PasswordResource.java69
-rw-r--r--src/main/java/org/traccar/api/resource/PermissionsResource.java87
-rw-r--r--src/main/java/org/traccar/api/resource/PositionResource.java108
-rw-r--r--src/main/java/org/traccar/api/resource/ReportResource.java286
-rw-r--r--src/main/java/org/traccar/api/resource/ServerResource.java66
-rw-r--r--src/main/java/org/traccar/api/resource/SessionResource.java97
-rw-r--r--src/main/java/org/traccar/api/resource/StatisticsResource.java18
-rw-r--r--src/main/java/org/traccar/api/resource/UserResource.java89
-rw-r--r--src/main/java/org/traccar/api/security/LoginService.java99
-rw-r--r--src/main/java/org/traccar/api/security/PermissionsService.java211
-rw-r--r--src/main/java/org/traccar/api/security/SecurityRequestFilter.java (renamed from src/main/java/org/traccar/api/SecurityRequestFilter.java)39
-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/UserPrincipal.java (renamed from src/main/java/org/traccar/api/UserPrincipal.java)2
-rw-r--r--src/main/java/org/traccar/api/security/UserSecurityContext.java (renamed from src/main/java/org/traccar/api/UserSecurityContext.java)6
-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/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.java200
-rw-r--r--src/main/java/org/traccar/broadcast/NullBroadcastService.java36
-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.java1123
-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.java452
-rw-r--r--src/main/java/org/traccar/database/DeviceLookupService.java141
-rw-r--r--src/main/java/org/traccar/database/DeviceManager.java483
-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.java199
-rw-r--r--src/main/java/org/traccar/database/PermissionsManager.java516
-rw-r--r--src/main/java/org/traccar/database/SimpleObjectManager.java100
-rw-r--r--src/main/java/org/traccar/database/StatisticsManager.java19
-rw-r--r--src/main/java/org/traccar/database/UsersManager.java84
-rw-r--r--src/main/java/org/traccar/forward/EventData.java78
-rw-r--r--src/main/java/org/traccar/forward/EventForwarder.java20
-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.java103
-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/PositionForwarderJson.java86
-rw-r--r--src/main/java/org/traccar/forward/PositionForwarderKafka.java58
-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.java5
-rw-r--r--src/main/java/org/traccar/geocoder/BingMapsGeocoder.java5
-rw-r--r--src/main/java/org/traccar/geocoder/FactualGeocoder.java5
-rw-r--r--src/main/java/org/traccar/geocoder/GeoapifyGeocoder.java82
-rw-r--r--src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java6
-rw-r--r--src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java5
-rw-r--r--src/main/java/org/traccar/geocoder/Geocoder.java4
-rw-r--r--src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java5
-rw-r--r--src/main/java/org/traccar/geocoder/GoogleGeocoder.java5
-rw-r--r--src/main/java/org/traccar/geocoder/HereGeocoder.java6
-rw-r--r--src/main/java/org/traccar/geocoder/JsonGeocoder.java22
-rw-r--r--src/main/java/org/traccar/geocoder/LocationIqGeocoder.java29
-rw-r--r--src/main/java/org/traccar/geocoder/MapQuestGeocoder.java5
-rw-r--r--src/main/java/org/traccar/geocoder/MapTilerGeocoder.java5
-rw-r--r--src/main/java/org/traccar/geocoder/MapboxGeocoder.java5
-rw-r--r--src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java5
-rw-r--r--src/main/java/org/traccar/geocoder/NominatimGeocoder.java6
-rw-r--r--src/main/java/org/traccar/geocoder/OpenCageGeocoder.java11
-rw-r--r--src/main/java/org/traccar/geocoder/PositionStackGeocoder.java5
-rw-r--r--src/main/java/org/traccar/geocoder/TestGeocoder.java36
-rw-r--r--src/main/java/org/traccar/geocoder/TomTomGeocoder.java5
-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.java12
-rw-r--r--src/main/java/org/traccar/geolocation/UniversalGeolocationProvider.java14
-rw-r--r--src/main/java/org/traccar/geolocation/UnwiredGeolocationProvider.java16
-rw-r--r--src/main/java/org/traccar/handler/ComputedAttributesHandler.java24
-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.java153
-rw-r--r--src/main/java/org/traccar/handler/GeocoderHandler.java22
-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.java16
-rw-r--r--src/main/java/org/traccar/handler/OpenChannelHandler.java14
-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.java74
-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.java132
-rw-r--r--src/main/java/org/traccar/handler/events/OverspeedEventHandler.java135
-rw-r--r--src/main/java/org/traccar/helper/BitUtil.java4
-rw-r--r--src/main/java/org/traccar/helper/BufferUtil.java38
-rw-r--r--src/main/java/org/traccar/helper/Checksum.java15
-rw-r--r--src/main/java/org/traccar/helper/ClassScanner.java80
-rw-r--r--src/main/java/org/traccar/helper/Log.java18
-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/ObjectMapperContextResolver.java (renamed from src/main/java/org/traccar/api/ObjectMapperProvider.java)22
-rw-r--r--src/main/java/org/traccar/helper/Parser.java18
-rw-r--r--src/main/java/org/traccar/helper/PatternUtil.java2
-rw-r--r--src/main/java/org/traccar/helper/model/AttributeUtil.java94
-rw-r--r--src/main/java/org/traccar/helper/model/DeviceUtil.java33
-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.java68
-rw-r--r--src/main/java/org/traccar/mail/LogMailManager.java44
-rw-r--r--src/main/java/org/traccar/mail/MailManager.java31
-rw-r--r--src/main/java/org/traccar/mail/SmtpMailManager.java160
-rw-r--r--src/main/java/org/traccar/model/Attribute.java3
-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.java12
-rw-r--r--src/main/java/org/traccar/model/CellTower.java38
-rw-r--r--src/main/java/org/traccar/model/Command.java30
-rw-r--r--src/main/java/org/traccar/model/Device.java140
-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.java4
-rw-r--r--src/main/java/org/traccar/model/Event.java7
-rw-r--r--src/main/java/org/traccar/model/ExtendedModel.java39
-rw-r--r--src/main/java/org/traccar/model/Geofence.java22
-rw-r--r--src/main/java/org/traccar/model/Group.java3
-rw-r--r--src/main/java/org/traccar/model/Maintenance.java3
-rw-r--r--src/main/java/org/traccar/model/Network.java26
-rw-r--r--src/main/java/org/traccar/model/Notification.java6
-rw-r--r--src/main/java/org/traccar/model/Order.java3
-rw-r--r--src/main/java/org/traccar/model/Pair.java43
-rw-r--r--src/main/java/org/traccar/model/Permission.java109
-rw-r--r--src/main/java/org/traccar/model/Position.java26
-rw-r--r--src/main/java/org/traccar/model/QueuedCommand.java46
-rw-r--r--src/main/java/org/traccar/model/Server.java89
-rw-r--r--src/main/java/org/traccar/model/Statistics.java3
-rw-r--r--src/main/java/org/traccar/model/User.java68
-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.java102
-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.java22
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorFirebase.java133
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorMail.java26
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorNull.java12
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorPushover.java72
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorSms.java41
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorTelegram.java63
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorTraccar.java68
-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.java44
-rw-r--r--src/main/java/org/traccar/protocol/ArmoliProtocolDecoder.java151
-rw-r--r--src/main/java/org/traccar/protocol/ArmoliProtocolPoller.java (renamed from src/main/java/org/traccar/DeviceSession.java)31
-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.java40
-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.java5
-rw-r--r--src/main/java/org/traccar/protocol/BceProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/BceProtocolDecoder.java14
-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.java20
-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.java9
-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.java32
-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/Dsf22FrameDecoder.java44
-rw-r--r--src/main/java/org/traccar/protocol/Dsf22Protocol.java44
-rw-r--r--src/main/java/org/traccar/protocol/Dsf22ProtocolDecoder.java89
-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.java58
-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.java43
-rw-r--r--src/main/java/org/traccar/protocol/EnvotechProtocolDecoder.java116
-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.java31
-rw-r--r--src/main/java/org/traccar/protocol/FlespiProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/FlespiProtocolDecoder.java19
-rw-r--r--src/main/java/org/traccar/protocol/FlexApiProtocol.java43
-rw-r--r--src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java173
-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.java2
-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/GalileoProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/GalileoProtocolDecoder.java76
-rw-r--r--src/main/java/org/traccar/protocol/GatorProtocol.java14
-rw-r--r--src/main/java/org/traccar/protocol/GatorProtocolDecoder.java2
-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.java84
-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.java2
-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.java986
-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.java42
-rw-r--r--src/main/java/org/traccar/protocol/H02ProtocolEncoder.java12
-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.java10
-rw-r--r--src/main/java/org/traccar/protocol/HuaShengProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/HuabaoProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java445
-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.java43
-rw-r--r--src/main/java/org/traccar/protocol/JidoProtocolDecoder.java128
-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/Jt600Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Jt600ProtocolDecoder.java88
-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.java2
-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.java2
-rw-r--r--src/main/java/org/traccar/protocol/LaipacProtocol.java12
-rw-r--r--src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java8
-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.java8
-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.java97
-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.java27
-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.java14
-rw-r--r--src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java19
-rw-r--r--src/main/java/org/traccar/protocol/Minifinder2Protocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java28
-rw-r--r--src/main/java/org/traccar/protocol/MobilogixProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/MobilogixProtocolDecoder.java12
-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/NavtelecomFrameDecoder.java9
-rw-r--r--src/main/java/org/traccar/protocol/NavtelecomProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/NavtelecomProtocolDecoder.java93
-rw-r--r--src/main/java/org/traccar/protocol/NdtpV6FrameDecoder.java32
-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.java44
-rw-r--r--src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java124
-rw-r--r--src/main/java/org/traccar/protocol/OrbcommProtocolPoller.java74
-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.java2
-rw-r--r--src/main/java/org/traccar/protocol/OwnTracksProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java2
-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.java2
-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.java39
-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.java46
-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.java17
-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.java26
-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.java10
-rw-r--r--src/main/java/org/traccar/protocol/StartekProtocolDecoder.java49
-rw-r--r--src/main/java/org/traccar/protocol/StbProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/StbProtocolDecoder.java33
-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.java173
-rw-r--r--src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java92
-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.java83
-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/T800xProtocol.java19
-rw-r--r--src/main/java/org/traccar/protocol/T800xProtocolDecoder.java42
-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.java2
-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/TechtoCruzFrameDecoder.java44
-rw-r--r--src/main/java/org/traccar/protocol/TechtoCruzProtocol.java13
-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.java325
-rw-r--r--src/main/java/org/traccar/protocol/TeraTrackProtocol.java42
-rw-r--r--src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java79
-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.java60
-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.java10
-rw-r--r--src/main/java/org/traccar/protocol/TopinProtocolDecoder.java37
-rw-r--r--src/main/java/org/traccar/protocol/TotemProtocol.java27
-rw-r--r--src/main/java/org/traccar/protocol/TotemProtocolDecoder.java22
-rw-r--r--src/main/java/org/traccar/protocol/TotemProtocolEncoder.java38
-rw-r--r--src/main/java/org/traccar/protocol/TotemProtocolSmsEncoder.java37
-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/TramigoProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java2
-rw-r--r--src/main/java/org/traccar/protocol/TrvProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/TrvProtocolDecoder.java6
-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.java30
-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/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.java2
-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/WatchProtocol.java10
-rw-r--r--src/main/java/org/traccar/protocol/WatchProtocolDecoder.java81
-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.java18
-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/WondexProtocolEncoder.java2
-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.java46
-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/CsvExportProvider.java76
-rw-r--r--src/main/java/org/traccar/reports/Events.java133
-rw-r--r--src/main/java/org/traccar/reports/EventsReportProvider.java169
-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.java102
-rw-r--r--src/main/java/org/traccar/reports/Stops.java102
-rw-r--r--src/main/java/org/traccar/reports/StopsReportProvider.java110
-rw-r--r--src/main/java/org/traccar/reports/SummaryReportProvider.java (renamed from src/main/java/org/traccar/reports/Summary.java)120
-rw-r--r--src/main/java/org/traccar/reports/Trips.java100
-rw-r--r--src/main/java/org/traccar/reports/TripsReportProvider.java110
-rw-r--r--src/main/java/org/traccar/reports/common/ReportUtils.java399
-rw-r--r--src/main/java/org/traccar/reports/common/TripsConfig.java (renamed from src/main/java/org/traccar/reports/model/TripsConfig.java)67
-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/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/schedule/ScheduleManager.java28
-rw-r--r--src/main/java/org/traccar/schedule/ScheduleTask.java22
-rw-r--r--src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java42
-rw-r--r--src/main/java/org/traccar/schedule/TaskHealthCheck.java (renamed from src/main/java/org/traccar/api/HealthCheckService.java)70
-rw-r--r--src/main/java/org/traccar/schedule/TaskWebSocketKeepalive.java17
-rw-r--r--src/main/java/org/traccar/session/ConnectionManager.java374
-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.java425
-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.java65
-rw-r--r--src/main/java/org/traccar/session/state/OverspeedState.java88
-rw-r--r--src/main/java/org/traccar/sms/HttpSmsClient.java55
-rw-r--r--src/main/java/org/traccar/sms/SmsManager.java7
-rw-r--r--src/main/java/org/traccar/sms/SnsSmsClient.java33
-rw-r--r--src/main/java/org/traccar/speedlimit/OverpassSpeedLimitProvider.java10
-rw-r--r--src/main/java/org/traccar/storage/DatabaseModule.java103
-rw-r--r--src/main/java/org/traccar/storage/DatabaseStorage.java410
-rw-r--r--src/main/java/org/traccar/storage/MemoryStorage.java79
-rw-r--r--src/main/java/org/traccar/storage/QueryBuilder.java (renamed from src/main/java/org/traccar/database/QueryBuilder.java)124
-rw-r--r--src/main/java/org/traccar/storage/QueryIgnore.java (renamed from src/main/java/org/traccar/database/QueryIgnore.java)2
-rw-r--r--src/main/java/org/traccar/storage/Storage.java53
-rw-r--r--src/main/java/org/traccar/storage/StorageException.java32
-rw-r--r--src/main/java/org/traccar/storage/StorageName.java (renamed from src/main/java/org/traccar/database/QueryExtended.java)10
-rw-r--r--src/main/java/org/traccar/storage/query/Columns.java81
-rw-r--r--src/main/java/org/traccar/storage/query/Condition.java211
-rw-r--r--src/main/java/org/traccar/storage/query/Limit.java (renamed from src/main/java/org/traccar/database/OrderManager.java)16
-rw-r--r--src/main/java/org/traccar/storage/query/Order.java46
-rw-r--r--src/main/java/org/traccar/storage/query/Request.java58
-rw-r--r--src/main/java/org/traccar/web/ConsoleServlet.java16
-rw-r--r--src/main/java/org/traccar/web/ThrottlingFilter.java53
-rw-r--r--src/main/java/org/traccar/web/WebInjectionManagerFactory.java50
-rw-r--r--src/main/java/org/traccar/web/WebModule.java30
-rw-r--r--src/main/java/org/traccar/web/WebServer.java105
-rw-r--r--src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory1
-rw-r--r--src/test/java/org/traccar/BaseTest.java77
-rw-r--r--src/test/java/org/traccar/ProtocolTest.java27
-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.java9
-rw-r--r--src/test/java/org/traccar/config/ConfigTest.java2
-rw-r--r--src/test/java/org/traccar/database/DataManagerTest.java81
-rw-r--r--src/test/java/org/traccar/forward/PositionForwarderUrlTest.java42
-rw-r--r--src/test/java/org/traccar/geocoder/GeocoderTest.java40
-rw-r--r--src/test/java/org/traccar/geofence/GeofenceCircleTest.java17
-rw-r--r--src/test/java/org/traccar/geofence/GeofencePolygonTest.java41
-rw-r--r--src/test/java/org/traccar/geofence/GeofencePolylineTest.java50
-rw-r--r--src/test/java/org/traccar/geolocation/GeolocationProviderTest.java13
-rw-r--r--src/test/java/org/traccar/handler/ComputedAttributesTest.java6
-rw-r--r--src/test/java/org/traccar/handler/DistanceHandlerTest.java4
-rw-r--r--src/test/java/org/traccar/handler/FilterHandlerTest.java75
-rw-r--r--src/test/java/org/traccar/handler/MotionHandlerTest.java12
-rw-r--r--src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java16
-rw-r--r--src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java10
-rw-r--r--src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java13
-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/BufferUtilTest.java41
-rw-r--r--src/test/java/org/traccar/protocol/AdmFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ArmoliProtocolDecoderTest.java36
-rw-r--r--src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java10
-rw-r--r--src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/B2316ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/BceFrameDecoderTest.java26
-rw-r--r--src/test/java/org/traccar/protocol/BceProtocolDecoderTest.java15
-rw-r--r--src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/BstplProtocolDecoderTest.java21
-rw-r--r--src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java10
-rw-r--r--src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java7
-rw-r--r--src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/DingtekFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/DingtekProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java5
-rw-r--r--src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/DolphinProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Dsf22FrameDecoderTest.java23
-rw-r--r--src/test/java/org/traccar/protocol/Dsf22ProtocolDecoderTest.java24
-rw-r--r--src/test/java/org/traccar/protocol/DualcamFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/EasyTrackProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java19
-rw-r--r--src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/EnnfuProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java31
-rw-r--r--src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/FifotrackFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/FifotrackProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/FlexApiProtocolDecoderTest.java45
-rw-r--r--src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/FlexibleReportProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/FutureWayFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/FutureWayProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/G1rusProtocolDecoderTest.java18
-rw-r--r--src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java17
-rw-r--r--src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/GlobalSatProtocolEncoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java16
-rw-r--r--src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Gs100ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java42
-rw-r--r--src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/H02FrameDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java10
-rw-r--r--src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java10
-rw-r--r--src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/HoopoProtocolDecoderTest.java5
-rw-r--r--src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java50
-rw-r--r--src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/IotmProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ItsFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ItsProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/JidoProtocolDecoderTest.java21
-rw-r--r--src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/JsonFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java11
-rw-r--r--src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java4
-rwxr-xr-xsrc/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/L100FrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/LacakProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/LeafSpyProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Mavlink2ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/MegastekProtocolDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java18
-rw-r--r--src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/MictrackProtocolDecoderTest.java7
-rw-r--r--src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java9
-rw-r--r--src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java9
-rw-r--r--src/test/java/org/traccar/protocol/MobilogixProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/MoovboxProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/MotorProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java2
-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.java2
-rw-r--r--src/test/java/org/traccar/protocol/NavisetProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java7
-rw-r--r--src/test/java/org/traccar/protocol/NavtelecomProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/NdtpV6ProtocolDecoderTest.java18
-rw-r--r--src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/NetProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/NiotProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/OmnicommProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java24
-rw-r--r--src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/PacificTrackProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/PolteProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/PortmanProtocolEncoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/PstFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/PstProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/PstProtocolEncoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/Pt215ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/R12wProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/RadarProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/RfTrackProtocolDecoderTest.java19
-rw-r--r--src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java5
-rw-r--r--src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/S168ProtocolDecoderTest.java11
-rw-r--r--src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/SanulProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java10
-rw-r--r--src/test/java/org/traccar/protocol/StartekProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/StbProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java169
-rwxr-xr-xsrc/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/SwiftechProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java7
-rw-r--r--src/test/java/org/traccar/protocol/T57FrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java5
-rw-r--r--src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TechTltProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TechtoCruzFrameDecoderTest.java25
-rw-r--r--src/test/java/org/traccar/protocol/TechtoCruzProtocolDecoderTest.java5
-rw-r--r--src/test/java/org/traccar/protocol/TekFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TeltonikaFrameDecoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java24
-rw-r--r--src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TeraTrackProtocolDecoderTest.java21
-rw-r--r--src/test/java/org/traccar/protocol/ThinkPowerProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/ThurayaProtocolDecoderTest.java24
-rw-r--r--src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java82
-rw-r--r--src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java9
-rw-r--r--src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/TopinProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java5
-rw-r--r--src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java20
-rw-r--r--src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java5
-rw-r--r--src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java5
-rw-r--r--src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java5
-rw-r--r--src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/UlbotechProtocolEncoderTest.java4
-rw-r--r--src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/UuxProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/VnetProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java37
-rw-r--r--src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java5
-rw-r--r--src/test/java/org/traccar/protocol/WliFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/WliProtocolDecoderTest.java5
-rw-r--r--src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/Xexun2FrameEncoderTest.java21
-rw-r--r--src/test/java/org/traccar/protocol/Xexun2ProtocolDecoderTest.java9
-rw-r--r--src/test/java/org/traccar/protocol/Xexun2ProtocolEncoderTest.java29
-rw-r--r--src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java11
-rw-r--r--src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java6
-rw-r--r--src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java8
-rw-r--r--src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java2
-rw-r--r--src/test/java/org/traccar/reports/ReportUtilsTest.java162
-rw-r--r--src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java13
-rw-r--r--swagger.json13
-rw-r--r--templates/export/events.xlsxbin8763 -> 9023 bytes
-rw-r--r--templates/full/alarm.vm6
-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.vm6
-rw-r--r--templates/full/deviceOnline.vm6
-rw-r--r--templates/full/deviceOverspeed.vm4
-rw-r--r--templates/full/deviceStopped.vm4
-rw-r--r--templates/full/deviceUnknown.vm6
-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/deviceFuelIncrease.vm2
-rw-r--r--templates/short/media.vm2
-rwxr-xr-xtools/config-doc.py105
-rwxr-xr-xtools/recover.py49
-rwxr-xr-xtools/test-commands.py2
-rwxr-xr-xtools/test-generator.py18
-rwxr-xr-xtools/test-integration.py92
-rwxr-xr-xtools/test-map.py9
-rwxr-xr-xtools/test-performance.py2
-rwxr-xr-xtools/test-trips.py6
m---------traccar-web0
1213 files changed, 22077 insertions, 11337 deletions
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..4ceb88a7c
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,59 @@
+name: Build Installers
+
+on:
+ workflow_dispatch:
+ inputs:
+ version:
+ description: 'Version'
+ required: true
+ default: 'preview'
+
+jobs:
+ build:
+
+ runs-on: ubuntu-18.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: 14
+ cache: npm
+ cache-dependency-path: |
+ traccar-web/package-lock.json
+ traccar-web/modern/package-lock.json
+ - run: |
+ wget -q http://cdn.sencha.com/cmd/7.1.0.15/no-jre/SenchaCmd-7.1.0.15-linux-i386.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 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.4+8/OpenJDK17U-jdk_x64_windows_hotspot_17.0.4_8.zip
+ wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.4+8/OpenJDK17U-jdk_x64_linux_hotspot_17.0.4_8.tar.gz
+ wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.4+8/OpenJDK17U-jdk_arm_linux_hotspot_17.0.4_8.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 f2672aada..c005ef9e4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,4 +10,3 @@ nbactions.xml
.gradle
out
build
-src/main/java/org/traccar/protobuf
diff --git a/build.gradle b/build.gradle
index d9c70fc15..91ba2cd5c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,8 +1,8 @@
plugins {
id "java"
id "checkstyle"
- id "com.google.protobuf" version "0.8.16"
- id "org.kordamp.gradle.project-enforcer" version "0.9.0"
+ id "com.google.protobuf" version "0.8.19"
+ id "org.kordamp.gradle.project-enforcer" version "0.10.0"
}
repositories {
@@ -10,11 +10,11 @@ repositories {
}
ext {
- guiceVersion = "5.0.1"
- jettyVersion = "10.0.6" // jetty 11 javax to jakarta
- jerseyVersion = "2.34" // jersey 3 javax to jakarta
- jacksonVersion = "2.12.2" // same version as jersey-media-json-jackson dependency
- protobufVersion = "3.17.3"
+ guiceVersion = "5.1.0"
+ jettyVersion = "10.0.12" // jetty 11 javax to jakarta
+ jerseyVersion = "2.37" // jersey 3 javax to jakarta
+ jacksonVersion = "2.13.4" // same version as jersey-media-json-jackson dependency
+ protobufVersion = "3.21.9"
}
sourceCompatibility = "11"
@@ -22,13 +22,12 @@ compileJava.options.encoding = "UTF-8"
jar.destinationDirectory = file("$projectDir/target")
checkstyle {
- toolVersion = "8.26"
+ toolVersion = "10.3.4"
configFile = "gradle/checkstyle.xml" as File
checkstyleTest.enabled = false
}
protobuf {
- generatedFilesBaseDir = "$projectDir/src"
protoc {
artifact = "com.google.protobuf:protoc:$protobufVersion"
}
@@ -42,19 +41,20 @@ enforce {
dependencies {
implementation "commons-codec:commons-codec:1.15"
- implementation "com.h2database:h2:1.4.200"
- implementation "mysql:mysql-connector-java:8.0.26"
- implementation "org.postgresql:postgresql:42.2.23"
- implementation "com.microsoft.sqlserver:mssql-jdbc:9.4.0.jre11"
- implementation "com.zaxxer:HikariCP:5.0.0"
- implementation "io.netty:netty-all:4.1.66.Final"
- implementation "org.slf4j:slf4j-jdk14:2.0.0-alpha4"
+ implementation "com.h2database:h2:2.1.214"
+ implementation "com.mysql:mysql-connector-j:8.0.31"
+ implementation "org.postgresql:postgresql:42.5.1"
+ implementation "com.microsoft.sqlserver:mssql-jdbc:11.2.1.jre11"
+ implementation "com.zaxxer:HikariCP:5.0.1"
+ implementation "io.netty:netty-all:4.1.85.Final"
+ implementation "org.slf4j:slf4j-jdk14:2.0.5"
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:1.1.6"
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"
@@ -62,27 +62,35 @@ 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 "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion"
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr353:$jacksonVersion"
- implementation "org.liquibase:liquibase-core:4.4.3"
- implementation "com.sun.mail:javax.mail:1.6.2"
+ implementation "org.liquibase:liquibase-core:4.17.2"
+ implementation "com.sun.mail:jakarta.mail:1.6.7"
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 "org.apache.velocity:velocity:1.7" // needs upgrade
+ implementation "org.apache.velocity:velocity-tools:2.0" // needs upgrade
implementation "org.apache.commons:commons-collections4:4.4"
- implementation "org.mnode.ical4j:ical4j:3.0.29"
+ implementation "org.mnode.ical4j:ical4j:3.2.7"
implementation "org.locationtech.spatial4j:spatial4j:0.8"
- implementation "org.locationtech.jts:jts-core:1.18.1"
- implementation "net.java.dev.jna:jna-platform:5.8.0"
- implementation "com.github.jnr:jnr-posix:3.1.7"
+ implementation "org.locationtech.jts:jts-core:1.19.0"
+ implementation "net.java.dev.jna:jna-platform:5.12.1"
+ implementation "com.github.jnr:jnr-posix:3.1.16"
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 "com.sun.xml.bind:jaxb-core:3.0.2" // needs upgrade
+ implementation "com.sun.xml.bind:jaxb-impl:3.0.2" // needs upgrade
implementation "javax.activation:activation:1.1.1"
- implementation 'com.amazonaws:aws-java-sdk-sns:1.12.47'
+ implementation "com.amazonaws:aws-java-sdk-sns:1.12.349"
+ implementation "org.apache.kafka:kafka-clients:3.3.1"
+ implementation 'com.hivemq:hivemq-mqtt-client:1.3.0'
+ implementation("com.google.firebase:firebase-admin:9.1.1") {
+ exclude group: 'com.google.cloud', module: 'google-cloud-firestore'
+ exclude group: 'com.google.cloud', module: 'google-cloud-storage'
+ }
testImplementation "junit:junit:4.13.2"
+ testImplementation "org.mockito:mockito-core:4.+"
}
task copyDependencies(type: Copy) {
@@ -95,7 +103,7 @@ jar {
manifest {
attributes(
"Main-Class": "org.traccar.Main",
- "Implementation-Version": "4.14",
+ "Implementation-Version": "5.5",
"Class-Path": configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(" "))
}
}
diff --git a/debug.xml b/debug.xml
index 796442364..2569bb8cd 100644
--- a/debug.xml
+++ b/debug.xml
@@ -10,10 +10,14 @@
<entry key='web.debug'>true</entry>
<entry key='web.console'>true</entry>
- <entry key='geocoder.enable'>false</entry>
- <entry key='geocoder.type'>ban</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..a6a6f0ff7 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 -->
@@ -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.jar b/gradle/wrapper/gradle-wrapper.jar
index f3d88b1c2..41d9927a4 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 8cf6eb5ad..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-6.8.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 2fe81a7d9..1b6c78733 100755
--- a/gradlew
+++ b/gradlew
@@ -1,7 +1,7 @@
-#!/usr/bin/env sh
+#!/bin/sh
#
-# Copyright 2015 the original author or authors.
+# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,78 +17,113 @@
#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
# Attempt to set APP_HOME
+
# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
warn () {
echo "$*"
-}
+} >&2
die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
- JAVACMD="java"
+ JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -105,79 +140,95 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
fi
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
# Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
fi
- i=`expr $i + 1`
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
done
- case $i in
- 0) set -- ;;
- 1) set -- "$args0" ;;
- 2) set -- "$args0" "$args1" ;;
- 3) set -- "$args0" "$args1" "$args2" ;;
- 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
fi
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=`save "$@"`
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 9618d8d96..107acd32c 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -51,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -61,28 +64,14 @@ echo location of your Java installation.
goto fail
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
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-5.0.xml b/schema/changelog-5.0.xml
new file mode 100644
index 000000000..0e8474eef
--- /dev/null
+++ b/schema/changelog-5.0.xml
@@ -0,0 +1,33 @@
+<?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.0">
+
+ <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" />
+ </addColumn>
+
+ <addColumn tableName="tc_users">
+ <column name="disablereports" type="BOOLEAN" defaultValueBoolean="false" />
+ </addColumn>
+
+ <renameColumn tableName="tc_orders" oldColumnName="toAddress" newColumnName="toaddresstmp" columnDataType="VARCHAR(512)" />
+ <renameColumn tableName="tc_orders" oldColumnName="fromAddress" newColumnName="fromaddresstmp" columnDataType="VARCHAR(512)" />
+
+ <renameColumn tableName="tc_orders" oldColumnName="toaddresstmp" newColumnName="toaddress" columnDataType="VARCHAR(512)" />
+ <renameColumn tableName="tc_orders" oldColumnName="fromaddresstmp" newColumnName="fromaddress" columnDataType="VARCHAR(512)" />
+
+ </changeSet>
+
+</databaseChangeLog>
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..335f7b3a8
--- /dev/null
+++ b/schema/changelog-5.6.xml
@@ -0,0 +1,17 @@
+<?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>
+
+ </changeSet>
+
+</databaseChangeLog>
diff --git a/schema/changelog-master.xml b/schema/changelog-master.xml
index 245367de3..0835918c9 100644
--- a/schema/changelog-master.xml
+++ b/schema/changelog-master.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?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"
@@ -30,4 +30,12 @@
<include file="changelog-4.13.xml" relativeToChangelogFile="true" />
<include file="changelog-4.15.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" />
+
</databaseChangeLog>
diff --git a/setup/default.xml b/setup/default.xml
index f314413f1..c00d29384 100644
--- a/setup/default.xml
+++ b/setup/default.xml
@@ -11,11 +11,15 @@
-->
<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'>false</entry>
- <entry key='geocoder.type'>google</entry>
+ <entry key='geocoder.enable'>true</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>
<entry key='logger.level'>info</entry>
<entry key='logger.file'>./logs/tracker-server.log</entry>
@@ -25,8 +29,6 @@
<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>
@@ -37,33 +39,7 @@
<entry key='commands.queueing'>true</entry>
<entry key='database.ignoreUnknown'>true</entry>
- <entry key='database.generateQueries'>true</entry>
<entry key='database.changelog'>./schema/changelog-master.xml</entry>
-
- <entry key='database.loginUser'>
- SELECT * FROM tc_users
- WHERE email = :email OR login = :email
- </entry>
-
- <entry key='database.selectPositions'>
- SELECT * FROM tc_positions WHERE deviceId = :deviceId AND fixTime BETWEEN :from AND :to ORDER BY fixTime
- </entry>
-
- <entry key='database.selectLatestPositions'>
- SELECT tc_positions.* FROM tc_positions INNER JOIN tc_devices ON tc_positions.id = tc_devices.positionid;
- </entry>
-
- <entry key='database.updateLatestPosition'>
- UPDATE tc_devices SET positionId = :id WHERE id = :deviceId
- </entry>
-
- <entry key='database.selectEvents'>
- SELECT * FROM tc_events WHERE deviceId = :deviceId AND eventTime BETWEEN :from AND :to ORDER BY eventTime
- </entry>
-
- <entry key='database.selectStatistics'>
- SELECT * FROM tc_statistics WHERE captureTime BETWEEN :from AND :to ORDER BY captureTime
- </entry>
<entry key='gps103.port'>5001</entry>
<entry key='tk103.port'>5002</entry>
@@ -300,5 +276,16 @@
<entry key='dualcam.port'>5232</entry>
<entry key='xexun2.port'>5233</entry>
<entry key='techtocruz.port'>5234</entry>
+ <entry key='flexapi.port'>5235</entry>
+ <entry key='dsf22.port'>5236</entry>
+ <entry key='jido.port'>5237</entry>
+ <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>
</properties>
diff --git a/setup/environment.sh b/setup/environment.sh
deleted file mode 100644
index cb80a296a..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-debug-11.0.12.7-1/java-11-openjdk-debug-11.0.12.7-1.windows.ojdkbuild.x86_64.zip
-wget https://github.com/ojdkbuild/contrib_jdk11u-ci/releases/download/jdk-11.0.12%2B7/jdk-11.0.12-ojdkbuild-linux-x64.zip
-wget https://github.com/ojdkbuild/contrib_jdk11u-arm32-ci/releases/download/jdk-11.0.12%2B7/jdk-11.0.12-ojdkbuild-linux-armhf.zip
diff --git a/setup/package.sh b/setup/package.sh
index e5f976b79..71b86014f 100755
--- a/setup/package.sh
+++ b/setup/package.sh
@@ -61,17 +61,17 @@ 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
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*64_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 [ $PREREQ = false ]; then
info "Missing build requirements, aborting..."
@@ -81,13 +81,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 +119,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 --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 +133,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*$1_linux*.tar.gz
+ jlink --module-path jdk-*/jmods --add-modules java.se,jdk.charsets,jdk.crypto.ec --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,13 +148,13 @@ package_linux () {
package_linux_64 () {
info "Building Linux 64 installer"
- package_linux x64 64
+ package_linux 64
ok "Created Linux 64 installer"
}
package_linux_arm () {
info "Building Linux ARM installer"
- package_linux armhf arm
+ package_linux arm
ok "Created Linux ARM installer"
}
diff --git a/setup/traccar.iss b/setup/traccar.iss
index 316bc757b..28b33adfb 100644
--- a/setup/traccar.iss
+++ b/setup/traccar.iss
@@ -1,6 +1,6 @@
[Setup]
AppName=Traccar
-AppVersion=4.14
+AppVersion=5.5
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 c9f3a2346..b184da45c 100644
--- a/src/main/java/org/traccar/BasePipelineFactory.java
+++ b/src/main/java/org/traccar/BasePipelineFactory.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.
@@ -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,6 +23,7 @@ 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.ComputedAttributesHandler;
import org.traccar.handler.CopyAttributesHandler;
@@ -43,10 +45,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,26 +57,30 @@ import java.util.Map;
public abstract class BasePipelineFactory extends ChannelInitializer<Channel> {
- private final TrackerServer server;
+ private final Injector injector;
+ private final TrackerConnector connector;
private final String protocol;
private int timeout;
- public BasePipelineFactory(TrackerServer server, String protocol) {
- this.server = server;
+ public BasePipelineFactory(TrackerConnector connector, Config config, String protocol) {
+ this.injector = Main.getInjector();
+ this.connector = connector;
this.protocol = protocol;
- timeout = Context.getConfig().getInteger(Keys.PROTOCOL_TIMEOUT.withPrefix(protocol));
+ timeout = config.getInteger(Keys.PROTOCOL_TIMEOUT.withPrefix(protocol));
if (timeout == 0) {
- timeout = Context.getConfig().getInteger(Keys.SERVER_TIMEOUT);
+ timeout = config.getInteger(Keys.SERVER_TIMEOUT);
}
}
+ protected abstract void addTransportHandlers(PipelineBuilder pipeline);
+
protected abstract void addProtocolHandlers(PipelineBuilder pipeline);
@SafeVarargs
- private final void addHandlers(ChannelPipeline pipeline, Class<? extends ChannelHandler>... handlerClasses) {
+ 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));
}
}
}
@@ -97,15 +104,19 @@ public abstract class BasePipelineFactory extends ChannelInitializer<Channel> {
protected void initChannel(Channel channel) {
final ChannelPipeline pipeline = channel.pipeline();
- if (timeout > 0 && !server.isDatagram()) {
+ addTransportHandlers(pipeline::addLast);
+
+ if (timeout > 0 && !connector.isDatagram()) {
pipeline.addLast(new IdleStateHandler(timeout, 0, 0));
}
- pipeline.addLast(new OpenChannelHandler(server));
+ pipeline.addLast(new OpenChannelHandler(connector));
pipeline.addLast(new NetworkMessageHandler());
pipeline.addLast(new StandardLoggingHandler(protocol));
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 {
@@ -129,20 +140,20 @@ public abstract class BasePipelineFactory extends ChannelInitializer<Channel> {
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 bd3391822..d19fc307e 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 javax.annotation.Nullable;
+import javax.inject.Inject;
import java.net.SocketAddress;
import java.util.Arrays;
import java.util.Collection;
@@ -35,7 +38,9 @@ public abstract class BaseProtocol implements Protocol {
private final String name;
private final Set<String> supportedDataCommands = new HashSet<>();
private final Set<String> supportedTextCommands = new HashSet<>();
- private final List<TrackerServer> serverList = new LinkedList<>();
+ private final List<TrackerConnector> connectorList = new LinkedList<>();
+
+ private SmsManager smsManager;
private StringProtocolEncoder textCommandEncoder = null;
@@ -48,18 +53,27 @@ 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;
}
protected void addServer(TrackerServer server) {
- serverList.add(server);
+ connectorList.add(server);
+ }
+
+ protected void addClient(TrackerClient client) {
+ connectorList.add(client);
}
@Override
- public Collection<TrackerServer> getServerList() {
- return serverList;
+ public Collection<TrackerConnector> getConnectorList() {
+ return connectorList;
}
public void setSupportedDataCommands(String... commands) {
@@ -107,13 +121,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..382daf92f 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 javax.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..9c3934184 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 javax.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);
}
}
@@ -62,7 +79,7 @@ public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter
Object encodedCommand = encodeCommand(ctx.channel(), command);
StringBuilder s = new StringBuilder();
- s.append("[").append(ctx.channel().id().asShortText()).append("] ");
+ 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) {
diff --git a/src/main/java/org/traccar/BaseProtocolPoller.java b/src/main/java/org/traccar/BaseProtocolPoller.java
new file mode 100644
index 000000000..be6556374
--- /dev/null
+++ b/src/main/java/org/traccar/BaseProtocolPoller.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelDuplexHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.util.concurrent.Future;
+
+import java.net.SocketAddress;
+import java.util.concurrent.TimeUnit;
+
+public abstract class BaseProtocolPoller extends ChannelDuplexHandler {
+
+ private final long interval;
+ private Future<?> timeout;
+
+ public BaseProtocolPoller(long interval) {
+ this.interval = interval;
+ }
+
+ protected abstract void sendRequest(Channel channel, SocketAddress remoteAddress);
+
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) throws Exception {
+ super.channelActive(ctx);
+ if (interval > 0) {
+ timeout = ctx.executor().scheduleAtFixedRate(
+ () -> sendRequest(ctx.channel(), ctx.channel().remoteAddress()), 0, interval, TimeUnit.SECONDS);
+ }
+ }
+
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+ super.channelInactive(ctx);
+ if (timeout != null) {
+ timeout.cancel(false);
+ timeout = null;
+ }
+ }
+
+}
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..f79a36c85 100644
--- a/src/main/java/org/traccar/ExtendedObjectDecoder.java
+++ b/src/main/java/org/traccar/ExtendedObjectDecoder.java
@@ -21,18 +21,38 @@ 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.helper.DataConverter;
import org.traccar.model.Position;
+import javax.inject.Inject;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
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;
diff --git a/src/main/java/org/traccar/LifecycleObject.java b/src/main/java/org/traccar/LifecycleObject.java
new file mode 100644
index 000000000..fe0dc698a
--- /dev/null
+++ b/src/main/java/org/traccar/LifecycleObject.java
@@ -0,0 +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;
+
+public interface LifecycleObject {
+ void start() throws Exception;
+ void stop() throws Exception;
+}
diff --git a/src/main/java/org/traccar/Main.java b/src/main/java/org/traccar/Main.java
index 63e5c1f90..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,7 +19,13 @@ import com.google.inject.Guice;
import com.google.inject.Injector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.api.HealthCheckService;
+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;
@@ -28,7 +34,9 @@ import java.lang.management.OperatingSystemMXBean;
import java.lang.management.RuntimeMXBean;
import java.nio.charset.Charset;
import java.util.Locale;
-import java.util.Timer;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
public final class Main {
@@ -107,40 +115,39 @@ public final class Main {
}
}
- private static void scheduleHealthCheck() {
- HealthCheckService service = new HealthCheckService();
- if (service.isEnabled()) {
- new Timer().scheduleAtFixedRate(
- service.createTask(), service.getPeriod(), service.getPeriod());
- }
- }
-
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...");
- Context.getServerManager().start();
- if (Context.getWebServer() != null) {
- Context.getWebServer().start();
+ if (injector.getInstance(BroadcastService.class).singleInstance()) {
+ DeviceUtil.resetStatus(injector.getInstance(Storage.class));
}
- Context.getScheduleManager().start();
- scheduleHealthCheck();
+ 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...");
-
- Context.getScheduleManager().stop();
- if (Context.getWebServer() != null) {
- Context.getWebServer().stop();
+ LOGGER.info("Stopping server...");
+
+ for (var service : services) {
+ try {
+ service.stop();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
}
- Context.getServerManager().stop();
}));
} catch (Exception e) {
LOGGER.error("Main method error", e);
diff --git a/src/main/java/org/traccar/MainEventHandler.java b/src/main/java/org/traccar/MainEventHandler.java
index 4889f6a2e..877f03ae7 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,31 @@ 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.helper.DateUtil;
+import org.traccar.helper.NetworkUtil;
+import org.traccar.helper.model.PositionUtil;
+import org.traccar.model.Device;
import org.traccar.model.Position;
-
-import java.sql.SQLException;
+import org.traccar.session.ConnectionManager;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
import 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 +56,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 +81,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);
- } catch (SQLException error) {
+ 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 +144,25 @@ 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());
- }
-
@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 +170,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 11100f66e..55211d109 100644
--- a/src/main/java/org/traccar/MainModule.java
+++ b/src/main/java/org/traccar/MainModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 - 2021 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.
@@ -16,146 +16,161 @@
package org.traccar;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr353.JSR353Module;
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.apache.velocity.runtime.log.NullLogChute;
+import org.eclipse.jetty.util.URIUtil;
+import org.traccar.broadcast.BroadcastService;
+import org.traccar.broadcast.MulticastBroadcastService;
+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.StatisticsManager;
+import org.traccar.forward.EventForwarder;
+import org.traccar.forward.EventForwarderJson;
+import org.traccar.forward.EventForwarderKafka;
+import org.traccar.forward.EventForwarderMqtt;
+import org.traccar.forward.PositionForwarder;
+import org.traccar.forward.PositionForwarderJson;
+import org.traccar.forward.PositionForwarderKafka;
+import org.traccar.forward.PositionForwarderUrl;
import org.traccar.geocoder.AddressFormat;
import org.traccar.geocoder.BanGeocoder;
import org.traccar.geocoder.BingMapsGeocoder;
import org.traccar.geocoder.FactualGeocoder;
+import org.traccar.geocoder.GeoapifyGeocoder;
import org.traccar.geocoder.GeocodeFarmGeocoder;
import org.traccar.geocoder.GeocodeXyzGeocoder;
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 org.traccar.helper.ObjectMapperContextResolver;
+import org.traccar.helper.SanitizerModule;
+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.Storage;
+import org.traccar.web.WebServer;
import javax.annotation.Nullable;
+import javax.inject.Singleton;
import javax.ws.rs.client.Client;
-import io.netty.util.Timer;
-import org.traccar.speedlimit.OverpassSpeedLimitProvider;
-import org.traccar.speedlimit.SpeedLimitProvider;
+import javax.ws.rs.client.ClientBuilder;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Properties;
public class MainModule extends AbstractModule {
- @Provides
- public static ObjectMapper provideObjectMapper() {
- return Context.getObjectMapper();
- }
-
- @Provides
- public static Config provideConfig() {
- return Context.getConfig();
- }
-
- @Provides
- public static DataManager provideDataManager() {
- return Context.getDataManager();
- }
-
- @Provides
- public static IdentityManager provideIdentityManager() {
- return Context.getIdentityManager();
- }
+ private final String configFile;
- @Provides
- public static ConnectionManager provideConnectionManager() {
- return Context.getConnectionManager();
+ public MainModule(String configFile) {
+ this.configFile = configFile;
}
- @Provides
- public static Client provideClient() {
- return Context.getClient();
- }
-
- @Provides
- public static TripsConfig provideTripsConfig() {
- return Context.getTripsConfig();
+ @Override
+ protected void configure() {
+ bindConstant().annotatedWith(Names.named("configFile")).to(configFile);
+ bind(Config.class).asEagerSingleton();
+ bind(Storage.class).to(DatabaseStorage.class).in(Scopes.SINGLETON);
+ bind(Timer.class).to(HashedWheelTimer.class).in(Scopes.SINGLETON);
}
+ @Singleton
@Provides
- public static DeviceManager provideDeviceManager() {
- return Context.getDeviceManager();
+ public static ObjectMapper provideObjectMapper(Config config) {
+ ObjectMapper objectMapper = new ObjectMapper();
+ if (config.getBoolean(Keys.WEB_SANITIZE)) {
+ objectMapper.registerModule(new SanitizerModule());
+ }
+ objectMapper.registerModule(new JSR353Module());
+ objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ return objectMapper;
}
+ @Singleton
@Provides
- public static GeofenceManager provideGeofenceManager() {
- return Context.getGeofenceManager();
+ public static Client provideClient(ObjectMapperContextResolver objectMapperContextResolver) {
+ return ClientBuilder.newClient().register(objectMapperContextResolver);
}
+ @Singleton
@Provides
- public static CalendarManager provideCalendarManager() {
- return Context.getCalendarManager();
+ 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 AttributesManager provideAttributesManager() {
- return Context.getAttributesManager();
+ 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 MaintenancesManager provideMaintenancesManager() {
- return Context.getMaintenancesManager();
+ public static LdapProvider provideLdapProvider(Config config) {
+ if (config.hasKey(Keys.LDAP_URL)) {
+ return new LdapProvider(config);
+ }
+ 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);
@@ -166,60 +181,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, 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":
+ 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;
@@ -227,14 +270,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;
@@ -242,53 +285,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;
}
@@ -296,9 +297,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;
}
@@ -314,130 +315,70 @@ 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);
+ public static BroadcastService provideBroadcastService(
+ Config config, ObjectMapper objectMapper) throws IOException {
+ if (config.hasKey(Keys.BROADCAST_ADDRESS)) {
+ return new MulticastBroadcastService(config, objectMapper);
}
- return null;
+ return new NullBroadcastService();
}
@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 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 "kafka":
+ return new EventForwarderKafka(config, objectMapper);
+ case "mqtt":
+ return new EventForwarderMqtt(config, objectMapper);
+ default:
+ return new EventForwarderJson(config, client);
+ }
}
return null;
}
@Singleton
@Provides
- public static TimeHandler provideTimeHandler(Config config) {
- if (config.hasKey(Keys.TIME_OVERRIDE)) {
- return new TimeHandler(config);
+ 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 "kafka":
+ return new PositionForwarderKafka(config, objectMapper);
+ default:
+ return new PositionForwarderUrl(config, client, objectMapper);
+ }
}
return null;
}
@Singleton
@Provides
- public static DefaultDataHandler provideDefaultDataHandler(@Nullable DataManager dataManager) {
- if (dataManager != null) {
- return new DefaultDataHandler(dataManager);
+ public static VelocityEngine provideVelocityEngine(Config config) {
+ Properties properties = new Properties();
+ properties.setProperty("file.resource.loader.path", config.getString(Keys.TEMPLATES_ROOT) + "/");
+ properties.setProperty("runtime.log.logsystem.class", NullLogChute.class.getName());
+
+ if (config.hasKey(Keys.WEB_URL)) {
+ properties.setProperty("web.url", config.getString(Keys.WEB_URL).replaceAll("/$", ""));
+ } else {
+ String address;
+ try {
+ address = config.getString(Keys.WEB_ADDRESS, InetAddress.getLocalHost().getHostAddress());
+ } catch (UnknownHostException e) {
+ address = "localhost";
+ }
+ String url = URIUtil.newURI("http", address, config.getInteger(Keys.WEB_PORT), "", "");
+ properties.setProperty("web.url", url);
}
- return null;
- }
- @Singleton
- @Provides
- public static CommandResultEventHandler provideCommandResultEventHandler() {
- return new CommandResultEventHandler();
- }
-
- @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..83f91e937
--- /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 javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.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/Protocol.java b/src/main/java/org/traccar/Protocol.java
index aea69b353..bc9c99557 100644
--- a/src/main/java/org/traccar/Protocol.java
+++ b/src/main/java/org/traccar/Protocol.java
@@ -25,7 +25,7 @@ public interface Protocol {
String getName();
- Collection<TrackerServer> getServerList();
+ Collection<TrackerConnector> getConnectorList();
Collection<String> getSupportedDataCommands();
diff --git a/src/main/java/org/traccar/ServerManager.java b/src/main/java/org/traccar/ServerManager.java
index 935a821aa..57afb01fd 100644
--- a/src/main/java/org/traccar/ServerManager.java
+++ b/src/main/java/org/traccar/ServerManager.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,95 +15,80 @@
*/
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 java.io.File;
+import javax.inject.Inject;
+import javax.inject.Singleton;
import java.io.IOException;
import java.net.BindException;
-import java.net.URI;
+import java.net.ConnectException;
import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.nio.charset.StandardCharsets;
-import java.util.Enumeration;
+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;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-public class ServerManager {
+@Singleton
+public class ServerManager implements LifecycleObject {
private static final Logger LOGGER = LoggerFactory.getLogger(ServerManager.class);
- private final List<TrackerServer> serverList = new LinkedList<>();
+ private final List<TrackerConnector> connectorList = new LinkedList<>();
private final Map<String, BaseProtocol> protocolList = new ConcurrentHashMap<>();
- private void loadPackage(String packageName) throws IOException, URISyntaxException, ReflectiveOperationException {
-
- List<String> names = new LinkedList<>();
- String packagePath = packageName.replace('.', '/');
- URL packageUrl = getClass().getClassLoader().getResource(packagePath);
-
- if (packageUrl.getProtocol().equals("jar")) {
- String jarFileName = URLDecoder.decode(packageUrl.getFile(), StandardCharsets.UTF_8.name());
- try (JarFile jf = new JarFile(jarFileName.substring(5, jarFileName.indexOf("!")))) {
- Enumeration<JarEntry> jarEntries = jf.entries();
- while (jarEntries.hasMoreElements()) {
- String entryName = jarEntries.nextElement().getName();
- if (entryName.startsWith(packagePath) && entryName.length() > packagePath.length() + 5) {
- names.add(entryName.substring(packagePath.length() + 1, entryName.lastIndexOf('.')));
- }
- }
- }
- } else {
- File folder = new File(new URI(packageUrl.toString()));
- File[] files = folder.listFiles();
- if (files != null) {
- for (File actual: files) {
- String entryName = actual.getName();
- names.add(entryName.substring(0, entryName.lastIndexOf('.')));
- }
- }
+ @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 (String name : names) {
- Class<?> protocolClass = Class.forName(packageName + '.' + name);
- if (BaseProtocol.class.isAssignableFrom(protocolClass) && Context.getConfig().hasKey(
- Keys.PROTOCOL_PORT.withPrefix(BaseProtocol.nameFromClass(protocolClass)))) {
- BaseProtocol protocol = (BaseProtocol) protocolClass.getDeclaredConstructor().newInstance();
- serverList.addAll(protocol.getServerList());
- protocolList.put(protocol.getName(), protocol);
+ for (Class<?> protocolClass : ClassScanner.findSubclasses(BaseProtocol.class, "org.traccar.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);
+ }
}
}
}
- public ServerManager() throws IOException, URISyntaxException, ReflectiveOperationException {
- loadPackage("org.traccar.protocol");
- }
-
public BaseProtocol getProtocol(String name) {
return protocolList.get(name);
}
+ @Override
public void start() throws Exception {
- for (TrackerServer server: serverList) {
+ for (TrackerConnector connector: connectorList) {
try {
- server.start();
+ connector.start();
} catch (BindException e) {
- LOGGER.warn("Port {} is disabled due to conflict", server.getPort());
+ LOGGER.warn("Port disabled due to conflict", e);
+ } catch (ConnectException e) {
+ LOGGER.warn("Connection failed", e);
}
}
}
- public void stop() {
- for (TrackerServer server: serverList) {
- server.stop();
+ @Override
+ 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
new file mode 100644
index 000000000..2d6b227da
--- /dev/null
+++ b/src/main/java/org/traccar/TrackerClient.java
@@ -0,0 +1,125 @@
+/*
+ * 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;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.group.ChannelGroup;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.channel.socket.nio.NioSocketChannel;
+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;
+import javax.net.ssl.SSLEngine;
+import java.util.concurrent.TimeUnit;
+
+public abstract class TrackerClient implements TrackerConnector {
+
+ private final boolean secure;
+ private final long interval;
+
+ private final Bootstrap bootstrap;
+
+ private final int port;
+ private final String address;
+ private final String[] devices;
+
+ private final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
+
+ @Override
+ public boolean isDatagram() {
+ return false;
+ }
+
+ @Override
+ public boolean isSecure() {
+ return secure;
+ }
+
+ 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("[, ]");
+
+ BasePipelineFactory pipelineFactory = new BasePipelineFactory(this, config, protocol) {
+ @Override
+ protected void addTransportHandlers(PipelineBuilder pipeline) {
+ try {
+ if (isSecure()) {
+ SSLEngine engine = SSLContext.getDefault().createSSLEngine();
+ engine.setUseClientMode(true);
+ pipeline.addLast(new SslHandler(engine));
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ try {
+ TrackerClient.this.addProtocolHandlers(pipeline, config);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+
+ bootstrap = new Bootstrap()
+ .group(EventLoopGroupFactory.getWorkerGroup())
+ .channel(NioSocketChannel.class)
+ .handler(pipelineFactory);
+ }
+
+ protected abstract void addProtocolHandlers(PipelineBuilder pipeline, Config config) throws Exception;
+
+ public String[] getDevices() {
+ return devices;
+ }
+
+ @Override
+ public ChannelGroup getChannelGroup() {
+ return channelGroup;
+ }
+
+ @Override
+ public void start() throws Exception {
+ bootstrap.connect(address, port)
+ .syncUninterruptibly().channel().closeFuture().addListener(new GenericFutureListener<>() {
+ @Override
+ public void operationComplete(Future<? super Void> future) {
+ if (interval > 0) {
+ GlobalEventExecutor.INSTANCE.schedule(() -> {
+ bootstrap.connect(address, port)
+ .syncUninterruptibly().channel().closeFuture().addListener(this);
+ }, interval, TimeUnit.SECONDS);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void stop() {
+ channelGroup.close().awaitUninterruptibly();
+ }
+
+}
diff --git a/src/main/java/org/traccar/database/ManagableObjects.java b/src/main/java/org/traccar/TrackerConnector.java
index ec9549493..fc6e93399 100644
--- a/src/main/java/org/traccar/database/ManagableObjects.java
+++ b/src/main/java/org/traccar/TrackerConnector.java
@@ -1,6 +1,5 @@
/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.
@@ -14,14 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.database;
+package org.traccar;
-import java.util.Set;
+import io.netty.channel.group.ChannelGroup;
-public interface ManagableObjects {
+public interface TrackerConnector extends LifecycleObject {
- Set<Long> getUserItems(long userId);
+ boolean isDatagram();
- Set<Long> getManagedItems(long userId);
+ boolean isSecure();
+
+ ChannelGroup getChannelGroup();
}
diff --git a/src/main/java/org/traccar/TrackerServer.java b/src/main/java/org/traccar/TrackerServer.java
index 59ba123e2..0e0837cfb 100644
--- a/src/main/java/org/traccar/TrackerServer.java
+++ b/src/main/java/org/traccar/TrackerServer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2018 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.
@@ -23,78 +23,92 @@ import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
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;
+import javax.net.ssl.SSLEngine;
import java.net.InetSocketAddress;
-public abstract class TrackerServer {
+public abstract class TrackerServer implements TrackerConnector {
private final boolean datagram;
+ private final boolean secure;
+
+ @SuppressWarnings("rawtypes")
private final AbstractBootstrap bootstrap;
+ private final int port;
+ private final String address;
+
+ private final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
+
+ @Override
public boolean isDatagram() {
return datagram;
}
- public TrackerServer(boolean datagram, String protocol) {
- this.datagram = datagram;
+ @Override
+ public boolean isSecure() {
+ return secure;
+ }
- 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, config, protocol) {
+ @Override
+ protected void addTransportHandlers(PipelineBuilder pipeline) {
+ try {
+ if (isSecure()) {
+ SSLEngine engine = SSLContext.getDefault().createSSLEngine();
+ pipeline.addLast(new SslHandler(engine));
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
- BasePipelineFactory pipelineFactory = new BasePipelineFactory(this, protocol) {
@Override
protected void addProtocolHandlers(PipelineBuilder pipeline) {
- TrackerServer.this.addProtocolHandlers(pipeline);
+ TrackerServer.this.addProtocolHandlers(pipeline, config);
}
};
+ this.datagram = datagram;
if (datagram) {
-
- this.bootstrap = new Bootstrap()
+ bootstrap = new Bootstrap()
.group(EventLoopGroupFactory.getWorkerGroup())
.channel(NioDatagramChannel.class)
.handler(pipelineFactory);
-
} else {
-
- this.bootstrap = new ServerBootstrap()
+ bootstrap = new ServerBootstrap()
.group(EventLoopGroupFactory.getBossGroup(), EventLoopGroupFactory.getWorkerGroup())
.channel(NioServerSocketChannel.class)
.childHandler(pipelineFactory);
-
}
}
- protected abstract void addProtocolHandlers(PipelineBuilder pipeline);
-
- private int port;
+ protected abstract void addProtocolHandlers(PipelineBuilder pipeline, Config config);
public int getPort() {
return port;
}
- public void setPort(int port) {
- this.port = port;
- }
-
- private String address;
-
public String getAddress() {
return address;
}
- public void setAddress(String address) {
- this.address = address;
- }
-
- private final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
-
+ @Override
public ChannelGroup getChannelGroup() {
return channelGroup;
}
+ @Override
public void start() throws Exception {
InetSocketAddress endpoint;
if (address == null) {
@@ -103,12 +117,13 @@ public abstract class TrackerServer {
endpoint = new InetSocketAddress(address, port);
}
- Channel channel = bootstrap.bind(endpoint).sync().channel();
+ Channel channel = bootstrap.bind(endpoint).syncUninterruptibly().channel();
if (channel != null) {
getChannelGroup().add(channel);
}
}
+ @Override
public void stop() {
channelGroup.close().awaitUninterruptibly();
}
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..91a745eeb 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.inject.Inject;
+import javax.inject.Singleton;
import javax.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 71f3939cb..904781e54 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,9 +16,19 @@
*/
package org.traccar.api;
-import java.sql.SQLException;
-import java.util.Set;
-
+import org.traccar.helper.LogAction;
+import org.traccar.model.BaseModel;
+import org.traccar.model.Group;
+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 javax.inject.Inject;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
@@ -27,58 +37,26 @@ 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.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.User;
-
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 {
@@ -87,103 +65,64 @@ public abstract class BaseObjectResource<T extends BaseModel> extends BaseResour
}
@POST
- public Response add(T entity) throws SQLException {
- 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());
- }
+ public Response add(T entity) throws StorageException {
+ 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);
+ 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());
- if (manager instanceof SimpleObjectManager) {
- ((SimpleObjectManager<T>) manager).refreshUserItems();
- } else if (baseClass.equals(Group.class) || baseClass.equals(Device.class)) {
- Context.getPermissionsManager().refreshDeviceAndGroupPermissions();
- Context.getPermissionsManager().refreshAllExtendedPermissions();
- }
return Response.ok(entity).build();
}
@Path("{id}")
@PUT
- public Response update(T entity) throws SQLException {
- 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());
+ public Response update(T entity) throws StorageException {
+ 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 SQLException {
- 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);
+ public Response remove(@PathParam("id") long id) throws StorageException {
+ 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 cc272df9c..33abe73fa 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,13 +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.inject.Inject;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;
public class BaseResource {
- @javax.ws.rs.core.Context
+ @Context
private SecurityContext securityContext;
+ @Inject
+ protected Storage storage;
+
+ @Inject
+ protected PermissionsService permissionsService;
+
protected long getUserId() {
UserPrincipal principal = (UserPrincipal) securityContext.getUserPrincipal();
if (principal != null) {
@@ -29,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..67d0341a1 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.inject.Inject;
+import javax.inject.Singleton;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.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/ExtendedObjectResource.java b/src/main/java/org/traccar/api/ExtendedObjectResource.java
index 9e554217e..8467b46c6 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 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 javax.ws.rs.GET;
import javax.ws.rs.QueryParam;
-
-import org.traccar.Context;
-import org.traccar.database.ExtendedObjectManager;
-import org.traccar.model.BaseModel;
+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..ab75bdc5d 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 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,20 @@
*/
package org.traccar.api;
-import java.io.IOException;
-import java.sql.SQLException;
+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 javax.inject.Inject;
+import javax.inject.Singleton;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
@@ -28,16 +39,24 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
+import java.io.IOException;
-import org.traccar.Context;
-import org.traccar.Main;
-import org.traccar.api.resource.SessionResource;
-import org.traccar.database.StatisticsManager;
-import org.traccar.helper.Log;
-import org.traccar.model.Device;
-
+@Singleton
public class MediaFilter implements Filter {
+ 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 init(FilterConfig filterConfig) throws ServletException {
}
@@ -45,6 +64,7 @@ public class MediaFilter implements Filter {
@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 +72,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,21 +83,19 @@ 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));
}
}
diff --git a/src/main/java/org/traccar/api/SimpleObjectResource.java b/src/main/java/org/traccar/api/SimpleObjectResource.java
index a7fcae0e7..4a435ca7d 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 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 javax.ws.rs.GET;
import javax.ws.rs.QueryParam;
-
-import org.traccar.Context;
-import org.traccar.database.BaseObjectManager;
-import org.traccar.model.BaseModel;
+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 de69d871c..f85e90133 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,8 +16,7 @@
*/
package org.traccar.api.resource;
-import java.sql.SQLException;
-
+import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
@@ -29,68 +28,72 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.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 SQLException {
- Context.getPermissionsManager().checkAdmin(getUserId());
+ public Response add(Attribute entity) throws StorageException {
+ permissionsService.checkAdmin(getUserId());
return super.add(entity);
}
@Path("{id}")
@PUT
- public Response update(Attribute entity) throws SQLException {
- Context.getPermissionsManager().checkAdmin(getUserId());
+ public Response update(Attribute entity) throws StorageException {
+ permissionsService.checkAdmin(getUserId());
return super.update(entity);
}
@Path("{id}")
@DELETE
- public Response remove(@PathParam("id") long id) throws SQLException {
- Context.getPermissionsManager().checkAdmin(getUserId());
+ public Response remove(@PathParam("id") long id) throws StorageException {
+ permissionsService.checkAdmin(getUserId());
return super.remove(id);
}
diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java
index a31345246..6ef6ee9c5 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,16 +17,24 @@
*/
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.model.Command;
+import org.traccar.model.Device;
+import org.traccar.model.Position;
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 java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
+import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
@@ -35,40 +43,80 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.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.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);
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getReadonly);
+ 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)) {
+ permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId());
+ if (!commandsManager.sendCommand(entity)) {
return Response.accepted(entity).build();
}
return Response.ok(entity).build();
@@ -78,15 +126,33 @@ public class CommandResource extends ExtendedObjectResource<Command> {
@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 7006cdb84..c0b0cea0d 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,33 +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.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+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.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-
-import java.sql.SQLException;
+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);
}
@@ -50,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 SQLException {
- if (!Context.getPermissionsManager().getUserAdmin(getUserId())) {
- Context.getPermissionsManager().checkManager(getUserId());
- Context.getPermissionsManager().checkPermission(Device.class, getUserId(), entity.getDeviceId());
+ public Response updateAccumulators(DeviceAccumulators entity) throws StorageException {
+ 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/EventResource.java b/src/main/java/org/traccar/api/resource/EventResource.java
index 34e4a94ce..afdaf52b5 100644
--- a/src/main/java/org/traccar/api/resource/EventResource.java
+++ b/src/main/java/org/traccar/api/resource/EventResource.java
@@ -15,7 +15,13 @@
*/
package org.traccar.api.resource;
-import java.sql.SQLException;
+import org.traccar.api.BaseResource;
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+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;
@@ -26,32 +32,20 @@ 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.Event;
-import org.traccar.model.Geofence;
-import org.traccar.model.Maintenance;
-
@Path("events")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
-
public class EventResource extends BaseResource {
@Path("{id}")
@GET
- public Event get(@PathParam("id") long id) throws SQLException {
- Event event = Context.getDataManager().getObject(Event.class, id);
+ public Event get(@PathParam("id") long id) throws StorageException {
+ 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/NotificationResource.java b/src/main/java/org/traccar/api/resource/NotificationResource.java
index 9631a52b7..2e4ad12f3 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 - 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,8 +15,18 @@
*/
package org.traccar.api.resource;
-import java.util.Collection;
+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 javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
@@ -25,20 +35,22 @@ 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.traccar.api.ExtendedObjectResource;
-import org.traccar.model.Event;
-import org.traccar.model.Notification;
-import org.traccar.model.Typed;
-import org.traccar.notification.MessageException;
-
+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, InterruptedException, StorageException {
+ User user = permissionsService.getUser(getUserId());
+ for (Typed method : notificatorManager.getAllNotificatorTypes()) {
+ notificatorManager.getNotificator(method.getType()).send(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, InterruptedException, StorageException {
+ User user = permissionsService.getUser(getUserId());
+ notificatorManager.getNotificator(notificator).send(user, new Event("test", 0), null);
return Response.noContent().build();
}
diff --git a/src/main/java/org/traccar/api/resource/PasswordResource.java b/src/main/java/org/traccar/api/resource/PasswordResource.java
index 1868a6191..2d87a8665 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,14 +15,18 @@
*/
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.inject.Inject;
import javax.mail.MessagingException;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
@@ -31,33 +35,35 @@ import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-import java.sql.SQLException;
-import java.util.UUID;
+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 SQLException, 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, 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 SQLException {
- 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 54d3964b6..d35cb98bb 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,12 +16,14 @@
*/
package org.traccar.api.resource;
-import java.sql.SQLException;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Set;
+import org.traccar.api.BaseResource;
+import org.traccar.helper.LogAction;
+import org.traccar.model.Permission;
+import org.traccar.model.UserRestrictions;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.storage.StorageException;
+import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
@@ -30,33 +32,24 @@ 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 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.getOwnerClass(), getUserId(), permission.getOwnerId());
}
- Context.getPermissionsManager().checkPermission(
- permission.getPropertyClass(), getUserId(), permission.getPropertyId());
}
private void checkPermissionTypes(List<LinkedHashMap<String, Long>> entities) {
@@ -71,49 +64,51 @@ public class PermissionsResource extends BaseResource {
@Path("bulk")
@POST
- public Response add(List<LinkedHashMap<String, Long>> entities) throws SQLException, ClassNotFoundException {
- Context.getPermissionsManager().checkReadonly(getUserId());
+ public Response add(List<LinkedHashMap<String, Long>> entities) throws StorageException, ClassNotFoundException {
+ 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();
}
@POST
- public Response add(LinkedHashMap<String, Long> entity) throws SQLException, ClassNotFoundException {
+ public Response add(LinkedHashMap<String, Long> entity) throws StorageException, ClassNotFoundException {
return add(Collections.singletonList(entity));
}
@DELETE
@Path("bulk")
- public Response remove(List<LinkedHashMap<String, Long>> entities) throws SQLException, ClassNotFoundException {
- Context.getPermissionsManager().checkReadonly(getUserId());
+ public Response remove(List<LinkedHashMap<String, Long>> entities) throws StorageException, ClassNotFoundException {
+ 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();
}
@DELETE
- public Response remove(LinkedHashMap<String, Long> entity) throws SQLException, ClassNotFoundException {
+ public Response remove(LinkedHashMap<String, Long> entity) throws StorageException, ClassNotFoundException {
return remove(Collections.singletonList(entity));
}
diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java
index 998d59706..042dd1e23 100644
--- a/src/main/java/org/traccar/api/resource/PositionResource.java
+++ b/src/main/java/org/traccar/api/resource/PositionResource.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.
@@ -15,20 +15,32 @@
*/
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.inject.Inject;
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.WebApplicationException;
+import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
-import java.sql.SQLException;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.Date;
import java.util.List;
@@ -37,29 +49,95 @@ import java.util.List;
@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 SQLException {
+ 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) {
- 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());
}
}
+ @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 7347bfd64..70177dd4d 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 - 2020 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,41 +16,47 @@
*/
package org.traccar.api.resource;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.sql.SQLException;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.api.BaseResource;
+import org.traccar.mail.MailManager;
+import org.traccar.helper.LogAction;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+import org.traccar.model.User;
+import org.traccar.model.UserRestrictions;
+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.model.StopReportItem;
+import org.traccar.reports.model.SummaryReportItem;
+import org.traccar.reports.model.TripReportItem;
+import org.traccar.storage.StorageException;
import javax.activation.DataHandler;
+import javax.inject.Inject;
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.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
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.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 javax.ws.rs.core.StreamingOutput;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
@Path("reports")
@Produces(MediaType.APPLICATION_JSON)
@@ -59,155 +65,267 @@ public class ReportResource extends BaseResource {
private static final Logger LOGGER = LoggerFactory.getLogger(ReportResource.class);
- private static final String XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
- private static final String CONTENT_DISPOSITION_VALUE_XLSX = "attachment; filename=report.xlsx";
+ private static final String EXCEL = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
+
+ @Inject
+ private EventsReportProvider eventsReportProvider;
+
+ @Inject
+ private RouteReportProvider routeReportProvider;
+
+ @Inject
+ private StopsReportProvider stopsReportProvider;
+
+ @Inject
+ private SummaryReportProvider summaryReportProvider;
+
+ @Inject
+ private TripsReportProvider tripsReportProvider;
+
+ @Inject
+ private MailManager mailManager;
private interface ReportExecutor {
- void execute(ByteArrayOutputStream stream) throws SQLException, IOException;
+ void execute(OutputStream stream) throws StorageException, IOException;
}
private Response executeReport(
- long userId, boolean mail, ReportExecutor executor) throws SQLException, IOException {
- final ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ long userId, boolean mail, ReportExecutor executor) {
if (mail) {
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")));
- Context.getMailManager().sendMessage(
- userId, "Report", "The report is in the attachment.", attachment);
- } catch (SQLException | IOException | MessagingException e) {
+ User user = permissionsService.getUser(userId);
+ mailManager.sendMessage(user, "Report", "The report is in the attachment.", attachment);
+ } catch (StorageException | IOException | MessagingException e) {
LOGGER.warn("Report failed", e);
}
}).start();
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("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 SQLException {
+ @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 SQLException, IOException {
+ @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 SQLException {
+ @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 SQLException, IOException {
+ @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 SQLException {
+ 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 SQLException, IOException {
+ @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 SQLException {
+ 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 SQLException, IOException {
+ @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 SQLException {
+ 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 SQLException, IOException {
+ @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 91488afff..4b7ee9189 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 - 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.
@@ -15,12 +15,23 @@
*/
package org.traccar.api.resource;
-import org.traccar.Context;
import org.traccar.api.BaseResource;
+import org.traccar.helper.model.UserUtil;
+import org.traccar.mail.MailManager;
+import org.traccar.geocoder.Geocoder;
+import org.traccar.helper.Log;
import org.traccar.helper.LogAction;
import org.traccar.model.Server;
+import org.traccar.model.User;
+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.annotation.Nullable;
import javax.annotation.security.PermitAll;
+import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
@@ -29,27 +40,52 @@ 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 java.util.Arrays;
+import java.util.Collection;
+import java.util.TimeZone;
@Path("server")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ServerResource extends BaseResource {
+ @Inject
+ private CacheManager cacheManager;
+
+ @Inject
+ private MailManager mailManager;
+
+ @Inject
+ @Nullable
+ private Geocoder geocoder;
+
@PermitAll
@GET
- public Server get(@QueryParam("force") boolean force) throws SQLException {
- if (force) {
- return Context.getDataManager().getServer();
+ public Server get() throws StorageException {
+ Server server = storage.getObject(Server.class, new Request(new Columns.All()));
+ server.setEmailEnabled(mailManager.getEmailEnabled());
+ server.setGeocoderEnabled(geocoder != null);
+ User user = permissionsService.getUser(getUserId());
+ if (user != null) {
+ if (user.getAdministrator()) {
+ server.setStorageSpace(Log.getStorageSpace());
+ }
} else {
- return Context.getPermissionsManager().getServer();
+ server.setNewServer(UserUtil.isEmpty(storage));
+ }
+ if (user != null && user.getAdministrator()) {
+ server.setStorageSpace(Log.getStorageSpace());
}
+ return server;
}
@PUT
- public Response update(Server entity) throws SQLException {
- Context.getPermissionsManager().checkAdmin(getUserId());
- Context.getPermissionsManager().updateServer(entity);
+ public Response update(Server entity) throws StorageException {
+ 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();
}
@@ -57,11 +93,17 @@ 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());
+ }
+
}
diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java
index e3c5d457f..7025d5fa7 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 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,14 +15,20 @@
*/
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.helper.DataConverter;
-import org.traccar.helper.ServletHelper;
import org.traccar.helper.LogAction;
+import org.traccar.helper.ServletHelper;
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.inject.Inject;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
@@ -31,16 +37,18 @@ import javax.ws.rs.FormParam;
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.QueryParam;
import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-
-import java.io.UnsupportedEncodingException;
+import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
-import java.sql.SQLException;
+import java.security.GeneralSecurityException;
+import java.util.Date;
@Path("session")
@Produces(MediaType.APPLICATION_JSON)
@@ -51,60 +59,86 @@ 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
+ private TokenManager tokenManager;
+
+ @Context
private HttpServletRequest request;
@PermitAll
@GET
- public User get(@QueryParam("token") String token) throws SQLException, UnsupportedEncodingException {
+ public User get(@QueryParam("token") String token) throws StorageException, IOException, GeneralSecurityException {
+
+ if (token != null) {
+ User user = loginService.login(token);
+ if (user != null) {
+ request.getSession().setAttribute(USER_ID_KEY, user.getId());
+ LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request));
+ return user;
+ }
+ }
+
Long userId = (Long) request.getSession().getAttribute(USER_ID_KEY);
if (userId == null) {
+
Cookie[] cookies = request.getCookies();
String email = null, password = null;
if (cookies != null) {
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);
- if (user != null) {
- userId = user.getId();
- request.getSession().setAttribute(USER_ID_KEY, userId);
- }
- } else if (token != null) {
- User user = Context.getUsersManager().getUserByToken(token);
+ User user = loginService.login(email, password);
if (user != null) {
- userId = user.getId();
- request.getSession().setAttribute(USER_ID_KEY, userId);
+ request.getSession().setAttribute(USER_ID_KEY, user.getId());
+ LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request));
+ return user;
}
}
- }
- if (userId != null) {
- Context.getPermissionsManager().checkUserEnabled(userId);
- return Context.getPermissionsManager().getUser(userId);
} else {
- throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
+
+ 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.checkAdmin(getUserId());
+ 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(), ServletHelper.retrieveRemoteAddress(request));
+ return user;
}
@PermitAll
@POST
public User add(
- @FormParam("email") String email, @FormParam("password") String password) throws SQLException {
- User user = Context.getPermissionsManager().login(email, password);
+ @FormParam("email") String email, @FormParam("password") String password) throws StorageException {
+ 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(), ServletHelper.retrieveRemoteAddress(request));
return user;
} else {
LogAction.failedLogin(ServletHelper.retrieveRemoteAddress(request));
@@ -114,9 +148,16 @@ public class SessionResource extends BaseResource {
@DELETE
public Response remove() {
- LogAction.logout(getUserId());
+ LogAction.logout(getUserId(), ServletHelper.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);
+ }
+
}
diff --git a/src/main/java/org/traccar/api/resource/StatisticsResource.java b/src/main/java/org/traccar/api/resource/StatisticsResource.java
index 58073e7d1..1f2296f28 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,9 +15,13 @@
*/
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;
@@ -25,7 +29,6 @@ import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
-import java.sql.SQLException;
import java.util.Collection;
import java.util.Date;
@@ -36,9 +39,12 @@ public class StatisticsResource extends BaseResource {
@GET
public Collection<Statistics> get(
- @QueryParam("from") Date from, @QueryParam("to") Date to) throws SQLException {
- Context.getPermissionsManager().checkAdmin(getUserId());
- return Context.getDataManager().getStatistics(from, to);
+ @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
+ 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 d54cc2382..e41ebbe61 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,15 +15,21 @@
*/
package org.traccar.api.resource;
-import org.traccar.Context;
import org.traccar.api.BaseObjectResource;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
-import org.traccar.database.UsersManager;
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.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
@@ -32,63 +38,82 @@ 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 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 SQLException {
- if (!Context.getPermissionsManager().getUserAdmin(getUserId())) {
- Context.getPermissionsManager().checkUserUpdate(getUserId(), new User(), entity);
- if (Context.getPermissionsManager().getUserManager(getUserId())) {
- Context.getPermissionsManager().checkUserLimit(getUserId());
+ public Response add(User entity) throws StorageException {
+ 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 (!permissionsService.getServer().getRegistration()) {
+ throw new SecurityException("Registration disabled");
+ }
+ entity.setDeviceLimit(config.getInteger(Keys.USERS_DEFAULT_DEVICE_LIMIT));
+ int expirationDays = config.getInteger(Keys.USERS_DEFAULT_EXPIRATION_DAYS);
if (expirationDays > 0) {
- entity.setExpirationTime(
- new Date(System.currentTimeMillis() + (long) expirationDays * 24 * 3600 * 1000));
+ entity.setExpirationTime(new Date(System.currentTimeMillis() + expirationDays * 86400000L));
}
}
}
- 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..88bafcfb5
--- /dev/null
+++ b/src/main/java/org/traccar/api/security/LoginService.java
@@ -0,0 +1,99 @@
+/*
+ * 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.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 javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+@Singleton
+public class LoginService {
+
+ private final Storage storage;
+ private final TokenManager tokenManager;
+ private final LdapProvider ldapProvider;
+
+ private final String serviceAccountToken;
+ private final boolean forceLdap;
+
+ @Inject
+ public LoginService(
+ Config config, Storage storage, TokenManager tokenManager, @Nullable LdapProvider ldapProvider) {
+ this.storage = storage;
+ this.tokenManager = tokenManager;
+ this.ldapProvider = ldapProvider;
+ serviceAccountToken = config.getString(Keys.WEB_SERVICE_ACCOUNT_TOKEN);
+ forceLdap = config.getBoolean(Keys.LDAP_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 {
+ 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;
+ }
+
+ 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..4421572d7
--- /dev/null
+++ b/src/main/java/org/traccar/api/security/PermissionsService.java
@@ -0,0 +1,211 @@
+/*
+ * 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 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.ScheduledModel;
+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 javax.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", object.getId())));
+ }
+ if (before == null || before.getGroupId() != after.getGroupId()) {
+ checkPermission(Group.class, userId, after.getGroupId());
+ }
+ }
+ }
+ if (object instanceof ScheduledModel) {
+ ScheduledModel after = ((ScheduledModel) object);
+ if (after.getCalendarId() > 0) {
+ ScheduledModel 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());
+ }
+ }
+ }
+ }
+ }
+
+ 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 = getUser(userId);
+ 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/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java
index 33b6b37df..94b6bbf05 100644
--- a/src/main/java/org/traccar/api/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 - 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,28 +13,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.api;
+package org.traccar.api.security;
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.inject.Inject;
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.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
+import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
-import java.sql.SQLException;
+import java.security.GeneralSecurityException;
public class SecurityRequestFilter implements ContainerRequestFilter {
@@ -43,6 +45,7 @@ public class SecurityRequestFilter implements ContainerRequestFilter {
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 BEARER_PREFIX = "Bearer ";
public static final String X_REQUESTED_WITH = "X-Requested-With";
public static final String XML_HTTP_REQUEST = "XMLHttpRequest";
@@ -55,12 +58,18 @@ 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;
+
@Override
public void filter(ContainerRequestContext requestContext) {
@@ -76,13 +85,18 @@ public class SecurityRequestFilter implements ContainerRequestFilter {
if (authHeader != null) {
try {
- String[] auth = decodeBasicAuth(authHeader);
- User user = Context.getPermissionsManager().login(auth[0], auth[1]);
+ User user;
+ if (authHeader.startsWith(BEARER_PREFIX)) {
+ user = loginService.login(authHeader.substring(BEARER_PREFIX.length()));
+ } 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 (SQLException e) {
+ } catch (StorageException | GeneralSecurityException | IOException e) {
throw new WebApplicationException(e);
}
@@ -90,8 +104,7 @@ 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);
+ statisticsManager.registerRequest(userId);
securityContext = new UserSecurityContext(new UserPrincipal(userId));
}
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/UserPrincipal.java b/src/main/java/org/traccar/api/security/UserPrincipal.java
index 175bca391..18b84a0e1 100644
--- a/src/main/java/org/traccar/api/UserPrincipal.java
+++ b/src/main/java/org/traccar/api/security/UserPrincipal.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.api;
+package org.traccar.api.security;
import java.security.Principal;
diff --git a/src/main/java/org/traccar/api/UserSecurityContext.java b/src/main/java/org/traccar/api/security/UserSecurityContext.java
index 55c0621bc..97df6b6c7 100644
--- a/src/main/java/org/traccar/api/UserSecurityContext.java
+++ b/src/main/java/org/traccar/api/security/UserSecurityContext.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.
@@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.api;
+package org.traccar.api.security;
import javax.ws.rs.core.SecurityContext;
import java.security.Principal;
public class UserSecurityContext implements SecurityContext {
- private UserPrincipal principal;
+ private final UserPrincipal principal;
public UserSecurityContext(UserPrincipal principal) {
this.principal = principal;
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..249d5bd97
--- /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 javax.inject.Inject;
+import javax.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..6a0d90b40
--- /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 javax.inject.Inject;
+import javax.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/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..b1b66f1e3
--- /dev/null
+++ b/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java
@@ -0,0 +1,200 @@
+/*
+ * 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 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 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.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class MulticastBroadcastService implements BroadcastService {
+
+ 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];
+
+ private final Set<BroadcastInterface> listeners = new HashSet<>();
+
+ 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
+ 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);
+ }
+
+ private 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);
+ }
+ }
+
+ private 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()));
+ }
+ }
+ }
+ }
+
+ @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/broadcast/NullBroadcastService.java b/src/main/java/org/traccar/broadcast/NullBroadcastService.java
new file mode 100644
index 000000000..f95037990
--- /dev/null
+++ b/src/main/java/org/traccar/broadcast/NullBroadcastService.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.broadcast;
+
+public class NullBroadcastService implements BroadcastService {
+
+ @Override
+ public boolean singleInstance() {
+ return true;
+ }
+
+ @Override
+ public void registerListener(BroadcastInterface listener) {
+ }
+
+ @Override
+ public void start() throws Exception {
+ }
+
+ @Override
+ public void stop() throws Exception {
+ }
+}
diff --git a/src/main/java/org/traccar/config/Config.java b/src/main/java/org/traccar/config/Config.java
index 815a6e86a..c73be6475 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 javax.inject.Inject;
+import javax.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 1411e8a13..09662fc85 100644
--- a/src/main/java/org/traccar/config/Keys.java
+++ b/src/main/java/org/traccar/config/Keys.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 - 2021 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,7 +15,7 @@
*/
package org.traccar.config;
-import java.util.Collections;
+import java.util.List;
public final class Keys {
@@ -25,17 +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 StringConfigSuffix(
+ ".devices",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Polling interval in seconds. Used only for polling protocols.
+ */
+ public static final ConfigSuffix<Long> PROTOCOL_INTERVAL = new LongConfigSuffix(
+ ".interval",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Enable SSL support for the protocol. Not all protocols support this.
+ */
+ public static final ConfigSuffix<Boolean> PROTOCOL_SSL = new BooleanConfigSuffix(
+ ".ssl",
+ List.of(KeyType.CONFIG));
/**
* Connection timeout value in seconds. Because sometimes there is no way to detect lost TCP connection old
@@ -43,567 +65,676 @@ 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 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 ConfigSuffix<>(
+ 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));
+
+ /**
+ * Protocol type for Suntech.
+ */
+ public static final ConfigKey<Integer> PROTOCOL_TYPE = new IntegerConfigKey(
+ "suntech.protocolType",
+ List.of(KeyType.CONFIG, KeyType.DEVICE));
+
+ /**
+ * Suntech HBM configuration value.
+ */
+ public static final ConfigKey<Boolean> PROTOCOL_HBM = new BooleanConfigKey(
+ "suntech.hbm",
+ List.of(KeyType.CONFIG, KeyType.DEVICE));
+
+ /**
+ * Format includes ADC value.
+ */
+ public static final ConfigSuffix<Boolean> PROTOCOL_INCLUDE_ADC = new BooleanConfigSuffix(
+ ".includeAdc",
+ List.of(KeyType.CONFIG, KeyType.DEVICE));
/**
- * Skip device connection session cache. Per protocol configuration.
+ * Format includes RPM value.
*/
- public static final ConfigSuffix<Boolean> PROTOCOL_IGNORE_SESSIONS_CACHE = new ConfigSuffix<>(
- ".ignoreSessionCache",
- Collections.singletonList(KeyType.GLOBAL));
+ public static final ConfigSuffix<Boolean> PROTOCOL_INCLUDE_RPM = new BooleanConfigSuffix(
+ ".includeRpm",
+ List.of(KeyType.CONFIG, KeyType.DEVICE));
/**
- * Skip device connection session cache. Global configuration.
+ * Format includes temperature values.
*/
- public static final ConfigKey<Boolean> DECODER_IGNORE_SESSIONS_CACHE = new ConfigKey<>(
- "decoder.ignoreSessionCache",
- Collections.singletonList(KeyType.GLOBAL));
+ public static final ConfigSuffix<Boolean> PROTOCOL_INCLUDE_TEMPERATURE = new BooleanConfigSuffix(
+ ".includeTemp",
+ List.of(KeyType.CONFIG, KeyType.DEVICE));
+
+ /**
+ * Protocol format. Used by protocols that have configurable message format.
+ */
+ public static final ConfigSuffix<String> PROTOCOL_FORMAT = new StringConfigSuffix(
+ ".format",
+ List.of(KeyType.DEVICE));
+
+ /**
+ * Protocol date format. Used by protocols that have configurable date format.
+ */
+ public static final ConfigSuffix<String> PROTOCOL_DATE_FORMAT = new StringConfigSuffix(
+ ".dateFormat",
+ List.of(KeyType.DEVICE));
+
+ /**
+ * Device time zone. Most devices report UTC time, but in some cases devices report local time, so this parameter
+ * needs to be configured for the server to be able to decode the time correctly.
+ */
+ public static final ConfigKey<String> DECODER_TIMEZONE = new StringConfigKey(
+ "decoder.timezone",
+ List.of(KeyType.CONFIG, KeyType.DEVICE));
+
+ /**
+ * ORBCOMM API access id.
+ */
+ public static final ConfigKey<String> ORBCOMM_ACCESS_ID = new StringConfigKey(
+ "orbcomm.accessId",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * ORBCOMM API password.
+ */
+ public static final ConfigKey<String> ORBCOMM_PASSWORD = new StringConfigKey(
+ "orbcomm.password",
+ List.of(KeyType.CONFIG));
+
+ /**
+ * Use alternative format for the protocol of commands.
+ */
+ 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));
/**
* 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));
/**
- * If true, the event is generated once at the beginning of overspeeding period.
+ * 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<Boolean> EVENT_OVERSPEED_NOT_REPEAT = new ConfigKey<>(
- "event.overspeed.notRepeat",
- Collections.singletonList(KeyType.GLOBAL));
+ 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);
/**
* 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));
/**
* 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),
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);
/**
* 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));
-
- /**
- * Automatically generate SQL database queries when possible.
- */
- public static final ConfigKey<Boolean> DATABASE_GENERATE_QUERIES = new ConfigKey<>(
- "database.generateQueries",
- 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));
+
+ /**
+ * 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
+ * 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));
-
- /**
- * Minimum device refresh timeout in seconds. Default timeout is 5 minutes.
- */
- public static final ConfigKey<Long> DATABASE_REFRESH_DELAY = new ConfigKey<>(
- "database.refreshDelay",
- Collections.singletonList(KeyType.GLOBAL),
- 300L);
+ List.of(KeyType.CONFIG));
/**
* 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.
*/
- 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));
/**
* 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));
+
+ /**
+ * 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.
*/
- public static final ConfigKey<Long> WEB_TIMEOUT = new ConfigKey<>(
+ public static final ConfigKey<Long> WEB_TIMEOUT = new LongConfigKey(
"web.timeout",
- Collections.singletonList(KeyType.GLOBAL),
+ List.of(KeyType.CONFIG),
60000L);
/**
* Authentication sessions timeout in seconds. By default no timeout.
*/
- public static final ConfigKey<Integer> WEB_SESSION_TIMEOUT = new ConfigKey<>(
+ public static final ConfigKey<Integer> WEB_SESSION_TIMEOUT = new IntegerConfigKey(
"web.sessionTimeout",
- Collections.singletonList(KeyType.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.
+ * Position forwarding format. Available options are "url", "json" and "kafka". Default is "url".
*/
- public static final ConfigKey<String> FORWARD_URL = new ConfigKey<>(
- "forward.url",
- Collections.singletonList(KeyType.GLOBAL));
+ public static final ConfigKey<String> FORWARD_TYPE = new StringConfigKey(
+ "forward.type",
+ List.of(KeyType.CONFIG),
+ "url");
/**
- * Additional HTTP header, can be used for authorization.
+ * Position forwarding Kafka topic.
*/
- public static final ConfigKey<String> FORWARD_HEADER = new ConfigKey<>(
- "forward.header",
- Collections.singletonList(KeyType.GLOBAL));
+ public static final ConfigKey<String> FORWARD_TOPIC = new StringConfigKey(
+ "forward.topic",
+ List.of(KeyType.CONFIG),
+ "positions");
/**
- * Boolean value to enable forwarding in JSON format.
+ * 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_JSON = new ConfigKey<>(
- "forward.json",
- Collections.singletonList(KeyType.GLOBAL));
+ public static final ConfigKey<String> FORWARD_URL = new StringConfigKey(
+ "forward.url",
+ List.of(KeyType.CONFIG));
/**
- * Boolean value to enable URL parameters in json mode. For example, {uniqueId} for device identifier,
- * {latitude} and {longitude} for coordinates.
+ * Additional HTTP header, can be used for authorization.
*/
- public static final ConfigKey<Boolean> FORWARD_URL_VARIABLES = new ConfigKey<>(
- "forward.urlVariables",
- Collections.singletonList(KeyType.GLOBAL));
+ 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
@@ -612,573 +743,745 @@ 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 Kafka topic.
+ */
+ 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));
+
+ /**
+ * Root folder for all template files.
+ */
+ 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));
+
+ /**
+ * 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));
/**
- * Enable commands queuing when devices are offline. Commands are buffered in memory only, so restarting service
- * will clear the buffer.
+ * The personal name for the email from address.
*/
- public static final ConfigKey<Boolean> COMMANDS_QUEUEING = new ConfigKey<>(
- "commands.queueing",
- Collections.singletonList(KeyType.GLOBAL));
+ 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));
/**
* 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),
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),
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),
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),
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));
+
+ /**
+ * 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));
/**
* 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 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 they're
- * marked as valid. Shouldn't be too low. Start testing with values at about 25000.
+ * 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));
+
+ /**
+ * 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 BooleanConfigKey(
+ "filter.relative",
+ List.of(KeyType.CONFIG));
/**
- * Time limit for the filtering in seconds. If the time difference between last position and a new one is more than
- * this limit, the new position will not be filtered out.
+ * 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));
/**
* 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.
@@ -1186,82 +1489,118 @@ 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 and report link.
+ * If not provided, Traccar will attempt to get a URL from the server IP address, but it might be a local address.
+ */
+ public static final ConfigKey<String> WEB_URL = new 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));
/**
* 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");
+ /**
+ * 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 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 be6310033..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.sql.SQLException;
-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;
-
-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 (SQLException 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 SQLException {
- 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 SQLException {
- dataManager.updateObject(item);
- updateCachedItem(item);
- }
-
- protected void removeCachedItem(long itemId) {
- try {
- writeLock();
- items.remove(itemId);
- } finally {
- writeUnlock();
- }
- }
-
- public void removeItem(long itemId) throws SQLException {
- 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..df399cd7a 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 javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.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 e12d44612..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 java.net.SocketAddress;
-import java.sql.SQLException;
-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 (SQLException error) {
- LOGGER.warn("Update device status error", error);
- }
-
- 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 00c802fde..000000000
--- a/src/main/java/org/traccar/database/DataManager.java
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * Copyright 2012 - 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.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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.config.Config;
-import org.traccar.config.Keys;
-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.Event;
-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.Position;
-import org.traccar.model.Server;
-import org.traccar.model.Statistics;
-import org.traccar.model.User;
-
-import javax.sql.DataSource;
-import java.beans.Introspector;
-import java.io.File;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
-
-public class DataManager {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(DataManager.class);
-
- public static final String ACTION_SELECT_ALL = "selectAll";
- public static final String ACTION_SELECT = "select";
- public static final String ACTION_INSERT = "insert";
- public static final String ACTION_UPDATE = "update";
- public static final String ACTION_DELETE = "delete";
-
- private final Config config;
-
- private DataSource dataSource;
-
- public DataSource getDataSource() {
- return dataSource;
- }
-
- private boolean generateQueries;
-
- private final boolean forceLdap;
-
- public DataManager(Config config) throws Exception {
- this.config = config;
-
- forceLdap = config.getBoolean(Keys.LDAP_FORCE);
-
- initDatabase();
- initDatabaseSchema();
- }
-
- 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);
- }
-
- generateQueries = config.getBoolean(Keys.DATABASE_GENERATE_QUERIES);
-
- dataSource = new HikariDataSource(hikariConfig);
- }
-
- public static String constructObjectQuery(String action, Class<?> clazz, boolean extended) {
- switch (action) {
- case ACTION_INSERT:
- case ACTION_UPDATE:
- StringBuilder result = new StringBuilder();
- StringBuilder fields = new StringBuilder();
- StringBuilder values = new StringBuilder();
-
- Set<Method> methods = new HashSet<>(Arrays.asList(clazz.getMethods()));
- methods.removeAll(Arrays.asList(Object.class.getMethods()));
- methods.removeAll(Arrays.asList(BaseModel.class.getMethods()));
- for (Method method : methods) {
- boolean skip;
- if (extended) {
- skip = !method.isAnnotationPresent(QueryExtended.class);
- } else {
- skip = method.isAnnotationPresent(QueryIgnore.class)
- || method.isAnnotationPresent(QueryExtended.class) && !action.equals(ACTION_INSERT);
- }
- if (!skip && method.getName().startsWith("get") && method.getParameterTypes().length == 0) {
- String name = Introspector.decapitalize(method.getName().substring(3));
- if (action.equals(ACTION_INSERT)) {
- fields.append(name).append(", ");
- values.append(":").append(name).append(", ");
- } else {
- fields.append(name).append(" = :").append(name).append(", ");
- }
- }
- }
- fields.setLength(fields.length() - 2);
- if (action.equals(ACTION_INSERT)) {
- values.setLength(values.length() - 2);
- result.append("INSERT INTO ").append(getObjectsTableName(clazz)).append(" (");
- result.append(fields).append(") ");
- result.append("VALUES (").append(values).append(")");
- } else {
- result.append("UPDATE ").append(getObjectsTableName(clazz)).append(" SET ");
- result.append(fields);
- result.append(" WHERE id = :id");
- }
- return result.toString();
- case ACTION_SELECT_ALL:
- return "SELECT * FROM " + getObjectsTableName(clazz);
- case ACTION_SELECT:
- return "SELECT * FROM " + getObjectsTableName(clazz) + " WHERE id = :id";
- case ACTION_DELETE:
- return "DELETE FROM " + getObjectsTableName(clazz) + " WHERE id = :id";
- default:
- throw new IllegalArgumentException("Unknown action");
- }
- }
-
- public static String constructPermissionQuery(String action, Class<?> owner, Class<?> property) {
- switch (action) {
- case ACTION_SELECT_ALL:
- return "SELECT " + makeNameId(owner) + ", " + makeNameId(property) + " FROM "
- + getPermissionsTableName(owner, property);
- case ACTION_INSERT:
- return "INSERT INTO " + getPermissionsTableName(owner, property)
- + " (" + makeNameId(owner) + ", " + makeNameId(property) + ") VALUES (:"
- + makeNameId(owner) + ", :" + makeNameId(property) + ")";
- case ACTION_DELETE:
- return "DELETE FROM " + getPermissionsTableName(owner, property)
- + " WHERE " + makeNameId(owner) + " = :" + makeNameId(owner)
- + " AND " + makeNameId(property) + " = :" + makeNameId(property);
- default:
- throw new IllegalArgumentException("Unknown action");
- }
- }
-
- private String getQuery(String key) {
- String query = config.getString(key);
- if (query == null) {
- LOGGER.info("Query not provided: " + key);
- }
- return query;
- }
-
- public String getQuery(String action, Class<?> clazz) {
- return getQuery(action, clazz, false);
- }
-
- public String getQuery(String action, Class<?> clazz, boolean extended) {
- String queryName;
- if (action.equals(ACTION_SELECT_ALL)) {
- queryName = "database.select" + clazz.getSimpleName() + "s";
- } else {
- queryName = "database." + action.toLowerCase() + clazz.getSimpleName();
- if (extended) {
- queryName += "Extended";
- }
- }
- String query = config.getString(queryName);
- if (query == null) {
- if (generateQueries) {
- query = constructObjectQuery(action, clazz, extended);
- } else {
- LOGGER.info("Query not provided: " + queryName);
- }
- }
- return query;
- }
-
- public String getQuery(String action, Class<?> owner, Class<?> property) {
- String queryName;
- switch (action) {
- case ACTION_SELECT_ALL:
- queryName = "database.select" + owner.getSimpleName() + property.getSimpleName() + "s";
- break;
- case ACTION_INSERT:
- queryName = "database.link" + owner.getSimpleName() + property.getSimpleName();
- break;
- default:
- queryName = "database.unlink" + owner.getSimpleName() + property.getSimpleName();
- break;
- }
- String query = config.getString(queryName);
- if (query == null) {
- if (generateQueries) {
- query = constructPermissionQuery(
- action, owner, property.equals(User.class) ? ManagedUser.class : property);
- } else {
- LOGGER.info("Query not provided: " + queryName);
- }
- }
- return query;
- }
-
- private static String getPermissionsTableName(Class<?> owner, Class<?> property) {
- String propertyName = property.getSimpleName();
- if (propertyName.equals("ManagedUser")) {
- propertyName = "User";
- }
- return "tc_" + Introspector.decapitalize(owner.getSimpleName())
- + "_" + Introspector.decapitalize(propertyName);
- }
-
- private static String getObjectsTableName(Class<?> clazz) {
- String result = "tc_" + Introspector.decapitalize(clazz.getSimpleName());
- // Add "s" ending if object name is not plural already
- if (!result.endsWith("s")) {
- result += "s";
- }
- return result;
- }
-
- 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 SQLException {
- User user = QueryBuilder.create(dataSource, getQuery("database.loginUser"))
- .setString("email", email.trim())
- .executeQuerySingle(User.class);
- 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 updateDeviceStatus(Device device) throws SQLException {
- QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, Device.class, true))
- .setObject(device)
- .executeUpdate();
- }
-
- public Collection<Position> getPositions(long deviceId, Date from, Date to) throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectPositions"))
- .setLong("deviceId", deviceId)
- .setDate("from", from)
- .setDate("to", to)
- .executeQuery(Position.class);
- }
-
- public void updateLatestPosition(Position position) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.updateLatestPosition"))
- .setDate("now", new Date())
- .setObject(position)
- .executeUpdate();
- }
-
- public Collection<Position> getLatestPositions() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectLatestPositions"))
- .executeQuery(Position.class);
- }
-
- public Server getServer() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, Server.class))
- .executeQuerySingle(Server.class);
- }
-
- public Collection<Event> getEvents(long deviceId, Date from, Date to) throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectEvents"))
- .setLong("deviceId", deviceId)
- .setDate("from", from)
- .setDate("to", to)
- .executeQuery(Event.class);
- }
-
- public Collection<Statistics> getStatistics(Date from, Date to) throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectStatistics"))
- .setDate("from", from)
- .setDate("to", to)
- .executeQuery(Statistics.class);
- }
-
- public static Class<?> getClassByName(String name) throws ClassNotFoundException {
- switch (name.toLowerCase().replace("id", "")) {
- case "device":
- return Device.class;
- case "group":
- return Group.class;
- case "user":
- return User.class;
- case "manageduser":
- return ManagedUser.class;
- case "geofence":
- return Geofence.class;
- case "driver":
- return Driver.class;
- case "attribute":
- return Attribute.class;
- case "calendar":
- return Calendar.class;
- case "command":
- return Command.class;
- case "maintenance":
- return Maintenance.class;
- case "notification":
- return Notification.class;
- case "order":
- return Order.class;
- default:
- throw new ClassNotFoundException();
- }
- }
-
- private static String makeNameId(Class<?> clazz) {
- String name = clazz.getSimpleName();
- return Introspector.decapitalize(name) + (!name.contains("Id") ? "Id" : "");
- }
-
- public Collection<Permission> getPermissions(Class<? extends BaseModel> owner, Class<? extends BaseModel> property)
- throws SQLException, ClassNotFoundException {
- return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, owner, property))
- .executePermissionsQuery();
- }
-
- public void linkObject(Class<?> owner, long ownerId, Class<?> property, long propertyId, boolean link)
- throws SQLException {
- QueryBuilder.create(dataSource, getQuery(link ? ACTION_INSERT : ACTION_DELETE, owner, property))
- .setLong(makeNameId(owner), ownerId)
- .setLong(makeNameId(property), propertyId)
- .executeUpdate();
- }
-
- public <T extends BaseModel> T getObject(Class<T> clazz, long entityId) throws SQLException {
- return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT, clazz))
- .setLong("id", entityId)
- .executeQuerySingle(clazz);
- }
-
- public <T extends BaseModel> Collection<T> getObjects(Class<T> clazz) throws SQLException {
- return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, clazz))
- .executeQuery(clazz);
- }
-
- public void addObject(BaseModel entity) throws SQLException {
- entity.setId(QueryBuilder.create(dataSource, getQuery(ACTION_INSERT, entity.getClass()), true)
- .setObject(entity)
- .executeUpdate());
- }
-
- public void updateObject(BaseModel entity) throws SQLException {
- QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, entity.getClass()))
- .setObject(entity)
- .executeUpdate();
- if (entity instanceof User && ((User) entity).getHashedPassword() != null) {
- QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, User.class, true))
- .setObject(entity)
- .executeUpdate();
- }
- }
-
- public void removeObject(Class<? extends BaseModel> clazz, long entityId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery(ACTION_DELETE, clazz))
- .setLong("id", entityId)
- .executeUpdate();
- }
-
-}
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..583b2ae35
--- /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 javax.inject.Inject;
+import javax.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 c8a99274c..000000000
--- a/src/main/java/org/traccar/database/DeviceManager.java
+++ /dev/null
@@ -1,483 +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;
-
-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 (SQLException e) {
- LOGGER.warn("Automatic device registration error", e);
- return 0;
- }
- }
-
- public void updateDeviceCache(boolean force) throws SQLException {
- 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;
- }
-
- public Device getDeviceByPhone(String phone) {
- try {
- readLock();
- return devicesByPhone.get(phone);
- } finally {
- readUnlock();
- }
- }
-
- @Override
- public Set<Long> getAllItems() {
- Set<Long> result = super.getAllItems();
- if (result.isEmpty()) {
- try {
- updateDeviceCache(true);
- } catch (SQLException e) {
- LOGGER.warn("Update device cache error", e);
- }
- 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 SQLException {
- 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 (SQLException 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 SQLException {
-
- 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 SQLException {
- 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 93e5820fb..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.sql.SQLException;
-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;
-
-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 SQLException {
- 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 (SQLException | 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 c35f35f93..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.sql.SQLException;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.traccar.Context;
-import org.traccar.model.Group;
-
-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 SQLException {
- 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..c1ef810ee 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 javax.inject.Inject;
+import javax.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 9f9a83cd2..cb971b082 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.sql.SQLException;
-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 javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.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);
- } catch (SQLException error) {
+ 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(user, event, position);
+ } catch (MessageException | InterruptedException 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/PermissionsManager.java b/src/main/java/org/traccar/database/PermissionsManager.java
deleted file mode 100644
index 32464cf90..000000000
--- a/src/main/java/org/traccar/database/PermissionsManager.java
+++ /dev/null
@@ -1,516 +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.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 java.sql.SQLException;
-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 (SQLException 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 (SQLException | 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 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 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()) {
- 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 SQLException {
- dataManager.updateObject(server);
- this.server = server;
- }
-
- public User login(String email, String password) throws SQLException {
- 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 eb8284d4e..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.sql.SQLException;
-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;
-
-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 (SQLException | ClassNotFoundException error) {
- LOGGER.warn("Error getting permissions", error);
- } finally {
- writeUnlock();
- }
- }
- }
-
- @Override
- public void removeItem(long itemId) throws SQLException {
- 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 4ad6d9d5c..e0995dabc 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.
@@ -23,12 +23,16 @@ 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 org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Request;
import javax.inject.Inject;
+import javax.inject.Singleton;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form;
-import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
@@ -37,6 +41,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 +49,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;
@@ -62,9 +67,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;
}
@@ -105,8 +110,8 @@ public class StatisticsManager {
}
try {
- dataManager.addObject(statistics);
- } catch (SQLException e) {
+ storage.addObject(statistics, new Request(new Columns.Exclude("id")));
+ } catch (StorageException e) {
LOGGER.warn("Error saving statistics", e);
}
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 b741a85b6..000000000
--- a/src/main/java/org/traccar/database/UsersManager.java
+++ /dev/null
@@ -1,84 +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;
-
-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
- 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/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/forward/EventForwarder.java b/src/main/java/org/traccar/forward/EventForwarder.java
new file mode 100644
index 000000000..1f991c0b5
--- /dev/null
+++ b/src/main/java/org/traccar/forward/EventForwarder.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 EventForwarder {
+ void forward(EventData eventData, ResultHandler resultHandler);
+}
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..7527d568a
--- /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 javax.ws.rs.client.Client;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.InvocationCallback;
+import javax.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..dc95cb4e2
--- /dev/null
+++ b/src/main/java/org/traccar/forward/EventForwarderMqtt.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.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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+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 static final Logger LOGGER = LoggerFactory.getLogger(EventForwarderMqtt.class);
+ 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().toString())
+ .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/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/PositionForwarderJson.java b/src/main/java/org/traccar/forward/PositionForwarderJson.java
new file mode 100644
index 000000000..27b96308e
--- /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 javax.ws.rs.client.Client;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.InvocationCallback;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.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/PositionForwarderUrl.java b/src/main/java/org/traccar/forward/PositionForwarderUrl.java
new file mode 100644
index 000000000..53cc7ad24
--- /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 javax.ws.rs.client.Client;
+import javax.ws.rs.client.InvocationCallback;
+import javax.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..f878a8bab 100644
--- a/src/main/java/org/traccar/geocoder/BanGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/BanGeocoder.java
@@ -22,11 +22,12 @@ package org.traccar.geocoder;
import javax.json.JsonArray;
import javax.json.JsonObject;
+import javax.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..01e33c2ea 100644
--- a/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java
@@ -18,11 +18,12 @@ package org.traccar.geocoder;
import javax.json.JsonArray;
import javax.json.JsonObject;
+import javax.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..384f46b0e 100644
--- a/src/main/java/org/traccar/geocoder/FactualGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/FactualGeocoder.java
@@ -17,6 +17,7 @@
package org.traccar.geocoder;
import javax.json.JsonObject;
+import javax.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
new file mode 100644
index 000000000..4748d6a2c
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/GeoapifyGeocoder.java
@@ -0,0 +1,82 @@
+/*
+ * 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 javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.ws.rs.client.Client;
+
+public class GeoapifyGeocoder extends JsonGeocoder {
+
+ private static String formatUrl(String key, String language) {
+ String url = "https://api.geoapify.com/v1/geocode/reverse?format=json&lat=%f&lon=%f";
+ if (key != null) {
+ url += "&apiKey=" + key;
+ }
+ if (language != null) {
+ url += "&lang=" + language;
+ }
+ return url;
+ }
+
+ public GeoapifyGeocoder(Client client, String key, String language, int cacheSize, AddressFormat addressFormat) {
+ super(client, formatUrl(key, language), cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ JsonArray results = json.getJsonArray("results");
+ if (results.size() > 0) {
+ JsonObject result = results.getJsonObject(0);
+
+ Address address = new Address();
+
+ if (json.containsKey("formatted")) {
+ address.setFormattedAddress(json.getString("formatted"));
+ }
+
+ if (result.containsKey("housenumber")) {
+ address.setHouse(result.getString("housenumber"));
+ }
+ if (result.containsKey("street")) {
+ address.setStreet(result.getString("street"));
+ }
+ if (result.containsKey("suburb")) {
+ address.setSuburb(result.getString("suburb"));
+ }
+ if (result.containsKey("city")) {
+ address.setSettlement(result.getString("city"));
+ }
+ if (result.containsKey("district")) {
+ address.setDistrict(result.getString("district"));
+ }
+ if (result.containsKey("state")) {
+ address.setState(result.getString("state"));
+ }
+ if (result.containsKey("country_code")) {
+ address.setCountry(result.getString("country_code").toUpperCase());
+ }
+ if (result.containsKey("postcode")) {
+ address.setPostcode(result.getString("postcode"));
+ }
+
+ return address;
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java b/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java
index 39a3300a0..2af95910f 100644
--- a/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java
@@ -16,6 +16,7 @@
package org.traccar.geocoder;
import javax.json.JsonObject;
+import javax.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..96491ece3 100644
--- a/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java
@@ -16,6 +16,7 @@
package org.traccar.geocoder;
import javax.json.JsonObject;
+import javax.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..0589eb000 100644
--- a/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java
@@ -16,6 +16,7 @@
package org.traccar.geocoder;
import javax.json.JsonObject;
+import javax.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..4d9ec8f36 100644
--- a/src/main/java/org/traccar/geocoder/GoogleGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/GoogleGeocoder.java
@@ -18,6 +18,7 @@ package org.traccar.geocoder;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonString;
+import javax.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..eb639995e 100644
--- a/src/main/java/org/traccar/geocoder/HereGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/HereGeocoder.java
@@ -16,6 +16,7 @@
package org.traccar.geocoder;
import javax.json.JsonObject;
+import javax.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..6105e8cfd 100644
--- a/src/main/java/org/traccar/geocoder/JsonGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/JsonGeocoder.java
@@ -17,13 +17,11 @@ 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.Client;
import javax.ws.rs.client.InvocationCallback;
import java.util.AbstractMap;
import java.util.Collections;
@@ -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/geocoder/LocationIqGeocoder.java b/src/main/java/org/traccar/geocoder/LocationIqGeocoder.java
new file mode 100644
index 000000000..f2ffe02d6
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/LocationIqGeocoder.java
@@ -0,0 +1,29 @@
+/*
+ * 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 javax.ws.rs.client.Client;
+
+public class LocationIqGeocoder extends NominatimGeocoder {
+
+ private static final String DEFAULT_URL = "https://us1.locationiq.com/v1/reverse.php";
+
+ 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..3f2554c6e 100644
--- a/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java
@@ -18,6 +18,7 @@ package org.traccar.geocoder;
import javax.json.JsonArray;
import javax.json.JsonObject;
+import javax.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..203f5f99b 100644
--- a/src/main/java/org/traccar/geocoder/MapTilerGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/MapTilerGeocoder.java
@@ -17,11 +17,12 @@ package org.traccar.geocoder;
import javax.json.JsonArray;
import javax.json.JsonObject;
+import javax.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..72bfb53f5 100644
--- a/src/main/java/org/traccar/geocoder/MapboxGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/MapboxGeocoder.java
@@ -18,6 +18,7 @@ package org.traccar.geocoder;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonString;
+import javax.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..dea295cca 100644
--- a/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java
@@ -17,11 +17,12 @@ package org.traccar.geocoder;
import javax.json.JsonArray;
import javax.json.JsonObject;
+import javax.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..b731549f7 100644
--- a/src/main/java/org/traccar/geocoder/NominatimGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/NominatimGeocoder.java
@@ -16,6 +16,7 @@
package org.traccar.geocoder;
import javax.json.JsonObject;
+import javax.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 56161e52c..fb61440aa 100644
--- a/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java
@@ -18,19 +18,24 @@ package org.traccar.geocoder;
import javax.json.JsonArray;
import javax.json.JsonObject;
+import javax.ws.rs.client.Client;
public class OpenCageGeocoder extends JsonGeocoder {
- private static String formatUrl(String url, String key) {
+ private static String formatUrl(String url, String key, String language) {
if (url == null) {
url = "https://api.opencagedata.com/geocode/v1";
}
url += "/json?q=%f,%f&no_annotations=1&key=" + key;
+ if (language != null) {
+ url += "&language=" + language;
+ }
return url;
}
- public OpenCageGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) {
- super(formatUrl(url, key), 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..9778d9eda 100644
--- a/src/main/java/org/traccar/geocoder/PositionStackGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/PositionStackGeocoder.java
@@ -17,6 +17,7 @@ package org.traccar.geocoder;
import javax.json.JsonArray;
import javax.json.JsonObject;
+import javax.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..9bb36efc2 100644
--- a/src/main/java/org/traccar/geocoder/TomTomGeocoder.java
+++ b/src/main/java/org/traccar/geocoder/TomTomGeocoder.java
@@ -17,6 +17,7 @@ package org.traccar.geocoder;
import javax.json.JsonArray;
import javax.json.JsonObject;
+import javax.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..8f0f3b704 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 javax.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..3b4ba4e1f 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 javax.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..82fcf42ab 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.Client;
import javax.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 f71620d8a..7a3f71ee1 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.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.InvocationCallback;
public class UniversalGeolocationProvider implements GeolocationProvider {
- private String url;
+ 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..14893b6a3 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.Client;
import javax.ws.rs.client.Entity;
import javax.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/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java
index 153da29b9..c9f1f63d7 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 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,28 +34,29 @@ 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 javax.inject.Inject;
+import javax.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 boolean includeDeviceAttributes;
- public ComputedAttributesHandler(
- Config config, IdentityManager identityManager, AttributesManager attributesManager) {
- this.identityManager = identityManager;
- this.attributesManager = attributesManager;
+ @Inject
+ public ComputedAttributesHandler(Config config, CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
engine = new JexlEngine();
engine.setStrict(true);
engine.setFunctions(Collections.singletonMap("math", Math.class));
@@ -65,7 +66,7 @@ public class ComputedAttributesHandler extends BaseDataHandler {
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));
@@ -104,8 +105,7 @@ public class ComputedAttributesHandler extends BaseDataHandler {
@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;
diff --git a/src/main/java/org/traccar/handler/CopyAttributesHandler.java b/src/main/java/org/traccar/handler/CopyAttributesHandler.java
index f386116b0..e5c9bc29a 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 javax.inject.Inject;
+import javax.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..89255a5fe 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 javax.inject.Inject;
+import javax.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..30dc9ff2b 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 javax.inject.Inject;
+import javax.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..c10fe9064 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 javax.inject.Inject;
+import javax.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 7cd9153c1..994276bb6 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 - 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,49 +19,83 @@ import io.netty.channel.ChannelHandler;
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.helper.UnitsConverter;
+import org.traccar.helper.model.AttributeUtil;
+import org.traccar.model.Device;
import org.traccar.model.Position;
-
+import org.traccar.session.cache.CacheManager;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Order;
+import org.traccar.storage.query.Request;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.util.Date;
+
+@Singleton
@ChannelHandler.Sharable
public class FilterHandler extends BaseDataHandler {
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 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 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 boolean filterRelative;
+ private final long skipLimit;
+ private final boolean skipAttributes;
+
+ private final CacheManager cacheManager;
+ private final Storage storage;
+
+ @Inject
+ public FilterHandler(Config config, CacheManager cacheManager, Storage storage) {
+ enabled = config.getBoolean(Keys.FILTER_ENABLE);
filterInvalid = config.getBoolean(Keys.FILTER_INVALID);
filterZero = config.getBoolean(Keys.FILTER_ZERO);
filterDuplicate = config.getBoolean(Keys.FILTER_DUPLICATE);
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;
+ 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;
+ }
+
+ 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) {
return filterInvalid && (!position.getValid()
- || position.getLatitude() > 90 || position.getLongitude() > 180
- || position.getLatitude() < -90 || position.getLongitude() < -180);
+ || position.getLatitude() > 90 || position.getLongitude() > 180
+ || position.getLatitude() < -90 || position.getLongitude() < -180);
}
private boolean filterZero(Position position) {
@@ -71,7 +105,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;
}
}
@@ -84,6 +118,10 @@ public class FilterHandler extends BaseDataHandler {
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;
}
@@ -129,10 +167,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;
}
}
@@ -144,51 +181,61 @@ public class FilterHandler extends BaseDataHandler {
StringBuilder filterType = new StringBuilder();
- Position last = null;
- if (Context.getIdentityManager() != null) {
- last = Context.getIdentityManager().getLastPosition(position.getDeviceId());
- }
-
+ // filter out invalid data
if (filterInvalid(position)) {
filterType.append("Invalid ");
}
if (filterZero(position)) {
filterType.append("Zero ");
}
- if (filterDuplicate(position, last) && !skipLimit(position, last) && !skipAttributes(position)) {
- filterType.append("Duplicate ");
- }
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 (filterStatic(position) && !skipLimit(position, last) && !skipAttributes(position)) {
- filterType.append("Static ");
- }
- if (filterDistance(position, last) && !skipLimit(position, last) && !skipAttributes(position)) {
- filterType.append("Distance ");
- }
- if (filterMaxSpeed(position, last)) {
- filterType.append("MaxSpeed ");
- }
- if (filterMinPeriod(position, last)) {
- filterType.append("MinPeriod ");
+
+ // filter out excessive data
+ long deviceId = position.getDeviceId();
+ if (filterDuplicate || filterStatic || filterDistance > 0 || filterMaxSpeed > 0 || filterMinPeriod > 0) {
+ Position preceding = null;
+ if (filterRelative) {
+ try {
+ Date newFixTime = position.getFixTime();
+ preceding = getPrecedingPosition(deviceId, newFixTime);
+ } catch (StorageException e) {
+ LOGGER.warn("Error retrieving preceding position; fallbacking to last received position.", e);
+ preceding = cacheManager.getPosition(deviceId);
+ }
+ } else {
+ preceding = cacheManager.getPosition(deviceId);
+ }
+ if (filterDuplicate(position, preceding) && !skipLimit(position, preceding) && !skipAttributes(position)) {
+ filterType.append("Duplicate ");
+ }
+ if (filterStatic(position) && !skipLimit(position, preceding) && !skipAttributes(position)) {
+ filterType.append("Static ");
+ }
+ if (filterDistance(position, preceding) && !skipLimit(position, preceding) && !skipAttributes(position)) {
+ filterType.append("Distance ");
+ }
+ if (filterMaxSpeed(position, preceding)) {
+ filterType.append("MaxSpeed ");
+ }
+ if (filterMinPeriod(position, preceding)) {
+ filterType.append("MinPeriod ");
+ }
}
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(position.getDeviceId()).getUniqueId());
-
- LOGGER.info(message.toString());
+ String uniqueId = cacheManager.getObject(Device.class, deviceId).getUniqueId();
+ LOGGER.info("Position filtered by {}filters from device: {}", filterType, uniqueId);
return true;
}
@@ -197,7 +244,7 @@ public class FilterHandler extends BaseDataHandler {
@Override
protected Position handlePosition(Position position) {
- if (filter(position)) {
+ if (enabled && filter(position)) {
return null;
}
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/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..ccbde9fe5 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 javax.inject.Inject;
+import javax.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..10312f9b3 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 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,19 +19,25 @@ package org.traccar.handler;
import io.netty.channel.ChannelHandler;
import org.traccar.BaseDataHandler;
import org.traccar.model.Position;
+import org.traccar.reports.common.TripsConfig;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+@Singleton
@ChannelHandler.Sharable
public class MotionHandler extends BaseDataHandler {
- private double speedThreshold;
+ private final double speedThreshold;
- public MotionHandler(double speedThreshold) {
- this.speedThreshold = speedThreshold;
+ @Inject
+ public MotionHandler(TripsConfig tripsConfig) {
+ speedThreshold = tripsConfig.getSpeedThreshold();
}
@Override
protected Position handlePosition(Position position) {
- if (!position.getAttributes().containsKey(Position.KEY_MOTION)) {
+ if (!position.hasAttribute(Position.KEY_MOTION)) {
position.set(Position.KEY_MOTION, position.getSpeed() > speedThreshold);
}
return position;
diff --git a/src/main/java/org/traccar/handler/OpenChannelHandler.java b/src/main/java/org/traccar/handler/OpenChannelHandler.java
index d09d617ab..e416f35ae 100644
--- a/src/main/java/org/traccar/handler/OpenChannelHandler.java
+++ b/src/main/java/org/traccar/handler/OpenChannelHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2019 - 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.
@@ -17,26 +17,26 @@ package org.traccar.handler;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
-import org.traccar.TrackerServer;
+import org.traccar.TrackerConnector;
public class OpenChannelHandler extends ChannelDuplexHandler {
- private final TrackerServer server;
+ private final TrackerConnector connector;
- public OpenChannelHandler(TrackerServer server) {
- this.server = server;
+ public OpenChannelHandler(TrackerConnector connector) {
+ this.connector = connector;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
- server.getChannelGroup().add(ctx.channel());
+ connector.getChannelGroup().add(ctx.channel());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
super.channelInactive(ctx);
- server.getChannelGroup().remove(ctx.channel());
+ connector.getChannelGroup().remove(ctx.channel());
}
}
diff --git a/src/main/java/org/traccar/handler/RemoteAddressHandler.java b/src/main/java/org/traccar/handler/RemoteAddressHandler.java
index c09b8c39a..e18d34ef2 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 javax.inject.Inject;
+import javax.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..0c6025999 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 javax.inject.Inject;
+import javax.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..c98b0bd4c 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 javax.inject.Inject;
+import javax.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..9f77df989 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 javax.inject.Inject;
+import javax.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..271aaa35d 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 javax.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..51bbd82d6 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 javax.inject.Inject;
+import javax.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..772176e9c 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 javax.inject.Inject;
+import javax.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..51fdc0307 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 javax.inject.Inject;
+import javax.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..462cc4223
--- /dev/null
+++ b/src/main/java/org/traccar/handler/events/FuelEventHandler.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ * 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 javax.inject.Inject;
+import javax.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 (change >= threshold) {
+ return Map.of(new Event(Event.TYPE_DEVICE_FUEL_INCREASE, position), position);
+ }
+ } else if (change < 0) {
+ double threshold = AttributeUtil.lookup(
+ cacheManager, Keys.EVENT_FUEL_DROP_THRESHOLD, position.getDeviceId());
+ if (Math.abs(change) >= threshold) {
+ 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..9414f4b31 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 - 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,59 @@
*/
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.config.Config;
+import org.traccar.helper.model.GeofenceUtil;
+import org.traccar.helper.model.PositionUtil;
import org.traccar.model.Calendar;
import org.traccar.model.Device;
import org.traccar.model.Event;
+import org.traccar.model.Geofence;
import org.traccar.model.Position;
+import org.traccar.session.ConnectionManager;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import 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 Config config;
+ private final CacheManager cacheManager;
private final ConnectionManager connectionManager;
+ private final Storage storage;
+ @Inject
public GeofenceEventHandler(
- IdentityManager identityManager, GeofenceManager geofenceManager, CalendarManager calendarManager,
- ConnectionManager connectionManager) {
- this.identityManager = identityManager;
- this.geofenceManager = geofenceManager;
- this.calendarManager = calendarManager;
+ Config config, CacheManager cacheManager, ConnectionManager connectionManager, Storage storage) {
+ this.config = config;
+ this.cacheManager = cacheManager;
this.connectionManager = connectionManager;
+ this.storage = storage;
}
@Override
protected Map<Event, Position> analyzePosition(Position position) {
- Device device = identityManager.getById(position.getDeviceId());
+ Device device = cacheManager.getObject(Device.class, position.getDeviceId());
if (device == null) {
return null;
}
- if (!identityManager.isLatestPosition(position) || !position.getValid()) {
+ if (!PositionUtil.isLatest(cacheManager, position) || !position.getValid()) {
return null;
}
- List<Long> currentGeofences = geofenceManager.getCurrentDeviceGeofences(position);
+ List<Long> currentGeofences = GeofenceUtil.getCurrentGeofences(config, cacheManager, position);
List<Long> oldGeofences = new ArrayList<>();
if (device.getGeofenceIds() != null) {
oldGeofences.addAll(device.getGeofenceIds());
@@ -66,15 +76,25 @@ public class GeofenceEventHandler extends BaseEventHandler {
newGeofences.removeAll(oldGeofences);
oldGeofences.removeAll(currentGeofences);
- device.setGeofenceIds(currentGeofences);
+
if (!oldGeofences.isEmpty() || !newGeofences.isEmpty()) {
- connectionManager.updateDevice(device);
+ device.setGeofenceIds(currentGeofences.isEmpty() ? null : currentGeofences);
+
+ try {
+ storage.updateObject(device, new Request(
+ new Columns.Include("geofenceIds"),
+ new Condition.Equals("id", device.getId())));
+ } catch (StorageException e) {
+ throw new RuntimeException("Update device geofences error", e);
+ }
+
+ connectionManager.updateDevice(true, device);
}
Map<Event, Position> events = new HashMap<>();
for (long geofenceId : oldGeofences) {
- 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_EXIT, position);
event.setGeofenceId(geofenceId);
@@ -82,8 +102,8 @@ public class GeofenceEventHandler extends BaseEventHandler {
}
}
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..b2e9a3325 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 javax.inject.Inject;
+import javax.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..909950acf 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 javax.inject.Inject;
+import javax.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..a49e08e8d
--- /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 javax.inject.Inject;
+import javax.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..c406bd935 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 - 2022 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,72 @@
*/
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.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 javax.inject.Inject;
+import javax.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 static final Logger LOGGER = LoggerFactory.getLogger(MotionEventHandler.class);
+
+ private final CacheManager cacheManager;
+ private final Storage storage;
private final TripsConfig tripsConfig;
- public MotionEventHandler(IdentityManager identityManager, DeviceManager deviceManager, TripsConfig tripsConfig) {
- this.identityManager = identityManager;
- this.deviceManager = deviceManager;
+ @Inject
+ public MotionEventHandler(
+ CacheManager cacheManager, Storage storage, TripsConfig tripsConfig) {
+ this.cacheManager = cacheManager;
+ this.storage = storage;
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);
- }
-
- 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;
- }
-
- 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;
- }
-
@Override
protected Map<Event, Position> analyzePosition(Position position) {
long deviceId = position.getDeviceId();
- Device device = identityManager.getById(deviceId);
+ Device device = cacheManager.getObject(Device.class, deviceId);
if (device == null) {
return null;
}
- if (!identityManager.isLatestPosition(position)
+ if (!PositionUtil.isLatest(cacheManager, position)
|| !tripsConfig.getProcessInvalidPositions() && !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);
+ 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..4d6aa8857 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 - 2022 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,65 @@
*/
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 javax.inject.Inject;
+import javax.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;
- 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;
- }
-
@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 +84,11 @@ public class OverspeedEventHandler extends BaseEventHandler {
double geofenceSpeedLimit = 0;
long overspeedGeofenceId = 0;
- if (geofenceManager != null && device.getGeofenceIds() != null) {
+ if (device.getGeofenceIds() != null) {
for (long geofenceId : device.getGeofenceIds()) {
- Geofence geofence = geofenceManager.getById(geofenceId);
+ 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 +106,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, 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 bbf12d738..d1025f548 100644
--- a/src/main/java/org/traccar/helper/BufferUtil.java
+++ b/src/main/java/org/traccar/helper/BufferUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 - 2021 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");
@@ -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,16 @@ 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);
}
- int result = ByteBufUtil.indexOf(needle, wrappedHaystack);
- return result < 0 ? result : haystack.readerIndex() + startIndex + result;
}
}
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
new file mode 100644
index 000000000..c928f6a12
--- /dev/null
+++ b/src/main/java/org/traccar/helper/ClassScanner.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;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Enumeration;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+public final class ClassScanner {
+
+ private ClassScanner() {
+ }
+
+ public static List<Class<?>> findSubclasses(
+ Class<?> baseClass) throws IOException, URISyntaxException, ReflectiveOperationException {
+ return findSubclasses(baseClass, baseClass.getPackageName());
+ }
+
+ public static List<Class<?>> findSubclasses(Class<?> baseClass, String packageName)
+ throws IOException, URISyntaxException, ReflectiveOperationException {
+
+ List<String> names = new LinkedList<>();
+ String packagePath = packageName.replace('.', '/');
+ URL packageUrl = baseClass.getClassLoader().getResource(packagePath);
+
+ if (packageUrl.getProtocol().equals("jar")) {
+ String jarFileName = URLDecoder.decode(packageUrl.getFile(), StandardCharsets.UTF_8.name());
+ try (JarFile jf = new JarFile(jarFileName.substring(5, jarFileName.indexOf("!")))) {
+ Enumeration<JarEntry> jarEntries = jf.entries();
+ while (jarEntries.hasMoreElements()) {
+ String entryName = jarEntries.nextElement().getName();
+ if (entryName.startsWith(packagePath) && entryName.length() > packagePath.length() + 5) {
+ names.add(entryName.substring(packagePath.length() + 1, entryName.lastIndexOf('.')));
+ }
+ }
+ }
+ } else {
+ File folder = new File(new URI(packageUrl.toString()));
+ File[] files = folder.listFiles();
+ if (files != null) {
+ for (File actual: files) {
+ String entryName = actual.getName();
+ names.add(entryName.substring(0, entryName.lastIndexOf('.')));
+ }
+ }
+ }
+
+ var classes = new LinkedList<Class<?>>();
+ for (String name : names) {
+ var clazz = Class.forName(packageName + '.' + name);
+ if (baseClass.isAssignableFrom(clazz)) {
+ classes.add(clazz);
+ }
+ }
+ return classes;
+ }
+
+}
diff --git a/src/main/java/org/traccar/helper/Log.java b/src/main/java/org/traccar/helper/Log.java
index 8c67f9ddc..e1b201f9f 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;
@@ -269,4 +273,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/api/ObjectMapperProvider.java b/src/main/java/org/traccar/helper/ObjectMapperContextResolver.java
index f81b20917..b40e30d76 100644
--- a/src/main/java/org/traccar/api/ObjectMapperProvider.java
+++ b/src/main/java/org/traccar/helper/ObjectMapperContextResolver.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,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.api;
+package org.traccar.helper;
import com.fasterxml.jackson.databind.ObjectMapper;
-import org.traccar.Context;
+import javax.inject.Inject;
import javax.ws.rs.ext.ContextResolver;
-import javax.ws.rs.ext.Provider;
-@Provider
-public class ObjectMapperProvider implements ContextResolver<ObjectMapper> {
+// 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<?> type) {
- return Context.getObjectMapper();
+ 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..aa39e1ad7 100644
--- a/src/main/java/org/traccar/helper/Parser.java
+++ b/src/main/java/org/traccar/helper/Parser.java
@@ -48,13 +48,14 @@ 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()) {
+ return true;
+ }
}
+ position += number;
+ return false;
}
public String next() {
@@ -155,6 +156,7 @@ public class Parser {
public enum CoordinateFormat {
DEG_DEG,
+ DEG_DEG_HEM,
DEG_HEM,
DEG_MIN_MIN,
DEG_MIN_HEM,
@@ -173,6 +175,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/model/AttributeUtil.java b/src/main/java/org/traccar/helper/model/AttributeUtil.java
new file mode 100644
index 000000000..43558e8f7
--- /dev/null
+++ b/src/main/java/org/traccar/helper/model/AttributeUtil.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2022 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.helper.model;
+
+import org.traccar.config.ConfigKey;
+import org.traccar.config.KeyType;
+import org.traccar.config.Keys;
+import org.traccar.model.Device;
+import org.traccar.model.Group;
+import org.traccar.session.cache.CacheManager;
+
+public final class AttributeUtil {
+
+ private AttributeUtil() {
+ }
+
+ @SuppressWarnings({ "deprecation", "unchecked" })
+ public static <T> T lookup(CacheManager cacheManager, ConfigKey<T> key, long deviceId) {
+ Device device = cacheManager.getObject(Device.class, deviceId);
+ Object result = device.getAttributes().get(key.getKey());
+ long groupId = device.getGroupId();
+ while (result == null && groupId > 0) {
+ Group group = cacheManager.getObject(Group.class, groupId);
+ if (group != null) {
+ result = group.getAttributes().get(key.getKey());
+ groupId = group.getGroupId();
+ } else {
+ groupId = 0;
+ }
+ }
+ if (result == null && key.hasType(KeyType.SERVER)) {
+ result = cacheManager.getServer().getAttributes().get(key.getKey());
+ }
+ if (result == null && key.hasType(KeyType.CONFIG)) {
+ result = cacheManager.getConfig().getString(key.getKey());
+ }
+
+ if (result != null) {
+ Class<T> valueClass = key.getValueClass();
+ if (valueClass.equals(Boolean.class)) {
+ return (T) (result instanceof String
+ ? Boolean.parseBoolean((String) result)
+ : result);
+ } else if (valueClass.equals(Integer.class)) {
+ return (T) (Object) (result instanceof String
+ ? Integer.parseInt((String) result)
+ : ((Number) result).intValue());
+ } else if (valueClass.equals(Long.class)) {
+ return (T) (Object) (result instanceof String
+ ? Long.parseLong((String) result)
+ : ((Number) result).longValue());
+ } else if (valueClass.equals(Double.class)) {
+ return (T) (Object) (result instanceof String
+ ? Double.parseDouble((String) result)
+ : ((Number) result).doubleValue());
+ } else {
+ return (T) result;
+ }
+ }
+ return key.getDefaultValue();
+ }
+
+ 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;
+ }
+
+}
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..597078caf
--- /dev/null
+++ b/src/main/java/org/traccar/helper/model/DeviceUtil.java
@@ -0,0 +1,33 @@
+/*
+ * 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.Device;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Request;
+
+public final class DeviceUtil {
+
+ private DeviceUtil() {
+ }
+
+ public static void resetStatus(Storage storage) throws StorageException {
+ storage.updateObject(new Device(), new Request(new Columns.Include("status")));
+ }
+
+}
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..9f93afeae
--- /dev/null
+++ b/src/main/java/org/traccar/helper/model/UserUtil.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.helper.model;
+
+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.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;
+ }
+
+}
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..b6b912d6c
--- /dev/null
+++ b/src/main/java/org/traccar/mail/LogMailManager.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.mail;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.model.User;
+
+import javax.mail.MessagingException;
+import javax.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, String subject, String body) throws MessagingException {
+ sendMessage(user, subject, body, null);
+ }
+
+ @Override
+ public void sendMessage(User user, String subject, String body, MimeBodyPart attachment) throws MessagingException {
+ LOGGER.info("\nTo: " + user.getEmail() + "\nSubject: " + subject + "\nBody:\n" + 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..69efbed32
--- /dev/null
+++ b/src/main/java/org/traccar/mail/MailManager.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.mail;
+
+import org.traccar.model.User;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeBodyPart;
+
+public interface MailManager {
+
+ boolean getEmailEnabled();
+
+ void sendMessage(User user, String subject, String body) throws MessagingException;
+
+ void sendMessage(User user, 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..4a0b7048f
--- /dev/null
+++ b/src/main/java/org/traccar/mail/SmtpMailManager.java
@@ -0,0 +1,160 @@
+/*
+ * 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 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.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);
+ }
+
+ public void sendMessage(
+ User user, String subject, String body) throws MessagingException {
+ sendMessage(user, subject, body, null);
+ }
+
+ public void sendMessage(
+ User user, 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) {
+ 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/model/Attribute.java b/src/main/java/org/traccar/model/Attribute.java
index 45d40b3ec..65f2e3881 100644
--- a/src/main/java/org/traccar/model/Attribute.java
+++ b/src/main/java/org/traccar/model/Attribute.java
@@ -16,6 +16,9 @@
*/
package org.traccar.model;
+import org.traccar.storage.StorageName;
+
+@StorageName("tc_attributes")
public class Attribute extends BaseModel {
private String description;
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 1010325b6..c1f98a957 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");
@@ -20,11 +20,12 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import net.fortuna.ical4j.data.CalendarBuilder;
import net.fortuna.ical4j.data.ParserException;
import net.fortuna.ical4j.filter.Filter;
-import net.fortuna.ical4j.filter.PeriodRule;
+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 org.traccar.database.QueryIgnore;
+import org.traccar.storage.QueryIgnore;
+import org.traccar.storage.StorageName;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -32,6 +33,7 @@ import java.time.Duration;
import java.util.Collection;
import java.util.Date;
+@StorageName("tc_calendars")
public class Calendar extends ExtendedModel {
private String name;
@@ -47,13 +49,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;
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 99930d1e6..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.
@@ -15,12 +15,14 @@
*/
package org.traccar.model;
-import org.traccar.database.QueryIgnore;
+import org.traccar.storage.QueryIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+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";
@@ -56,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";
@@ -83,25 +84,16 @@ public class Command extends Message implements Cloneable {
public static final String KEY_SERVER = "server";
public static final String KEY_PORT = "port";
+ @QueryIgnore
@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;
+ public long getDeviceId() {
+ return super.getDeviceId();
}
@QueryIgnore
@Override
- public long getDeviceId() {
- return super.getDeviceId();
+ public void setDeviceId(long deviceId) {
+ super.setDeviceId(deviceId);
}
private String description;
diff --git a/src/main/java/org/traccar/model/Device.java b/src/main/java/org/traccar/model/Device.java
index 0c9be932d..b8c87921d 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 - 2018 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,11 +17,14 @@ package org.traccar.model;
import java.util.Date;
import java.util.List;
+import java.util.stream.Collectors;
-import org.traccar.database.QueryExtended;
-import org.traccar.database.QueryIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.traccar.storage.QueryIgnore;
+import org.traccar.storage.StorageName;
-public class Device extends GroupedModel {
+@StorageName("tc_devices")
+public class Device extends GroupedModel implements Disableable {
private String name;
@@ -55,26 +58,18 @@ public class Device extends GroupedModel {
}
public void setStatus(String status) {
- this.status = status;
+ this.status = status != null ? status.trim() : null;
}
private Date lastUpdate;
- @QueryExtended
+ @QueryIgnore
public Date getLastUpdate() {
- if (lastUpdate != null) {
- return new Date(lastUpdate.getTime());
- } else {
- return null;
- }
+ return this.lastUpdate;
}
public void setLastUpdate(Date lastUpdate) {
- if (lastUpdate != null) {
- this.lastUpdate = new Date(lastUpdate.getTime());
- } else {
- this.lastUpdate = null;
- }
+ this.lastUpdate = lastUpdate;
}
private long positionId;
@@ -95,8 +90,12 @@ public class Device extends GroupedModel {
return geofenceIds;
}
- public void setGeofenceIds(List<Long> geofenceIds) {
- this.geofenceIds = 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;
+ }
}
private String phone;
@@ -141,12 +140,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 05f52fd4d..b9e023088 100644
--- a/src/main/java/org/traccar/model/Driver.java
+++ b/src/main/java/org/traccar/model/Driver.java
@@ -16,6 +16,9 @@
*/
package org.traccar.model;
+import org.traccar.storage.StorageName;
+
+@StorageName("tc_drivers")
public class Driver extends ExtendedModel {
private String name;
@@ -37,4 +40,5 @@ public class Driver extends ExtendedModel {
public void setUniqueId(String uniqueId) {
this.uniqueId = uniqueId;
}
+
}
diff --git a/src/main/java/org/traccar/model/Event.java b/src/main/java/org/traccar/model/Event.java
index a7a134ecf..0e851d748 100644
--- a/src/main/java/org/traccar/model/Event.java
+++ b/src/main/java/org/traccar/model/Event.java
@@ -15,8 +15,11 @@
*/
package org.traccar.model;
+import org.traccar.storage.StorageName;
+
import java.util.Date;
+@StorageName("tc_events")
public class Event extends Message {
public Event(String type, Position position) {
@@ -49,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";
@@ -59,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..7a61eda8c 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) {
@@ -86,7 +91,7 @@ public class ExtendedModel extends BaseModel {
public String getString(String key) {
if (attributes.containsKey(key)) {
- return (String) attributes.get(key);
+ return attributes.get(key).toString();
} else {
return null;
}
@@ -94,7 +99,12 @@ public class ExtendedModel extends BaseModel {
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 +112,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 +125,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 +138,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 85f392f99..9259028fb 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 - 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,24 +15,19 @@
*/
package org.traccar.model;
-import java.text.ParseException;
-
-import org.traccar.Context;
-import org.traccar.config.Keys;
-import org.traccar.database.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 org.traccar.storage.QueryIgnore;
+import org.traccar.storage.StorageName;
-import com.fasterxml.jackson.annotation.JsonIgnore;
+import java.text.ParseException;
+@StorageName("tc_geofences")
public class Geofence extends ScheduledModel {
- 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 String name;
public String getName() {
@@ -66,9 +61,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);
}
@@ -90,4 +83,5 @@ public class Geofence extends ScheduledModel {
area = geometry.toWkt();
this.geometry = geometry;
}
+
}
diff --git a/src/main/java/org/traccar/model/Group.java b/src/main/java/org/traccar/model/Group.java
index 91ea2319d..ff69f61fa 100644
--- a/src/main/java/org/traccar/model/Group.java
+++ b/src/main/java/org/traccar/model/Group.java
@@ -15,6 +15,9 @@
*/
package org.traccar.model;
+import org.traccar.storage.StorageName;
+
+@StorageName("tc_groups")
public class Group extends GroupedModel {
private String name;
diff --git a/src/main/java/org/traccar/model/Maintenance.java b/src/main/java/org/traccar/model/Maintenance.java
index 73f67ea96..cad100a3a 100644
--- a/src/main/java/org/traccar/model/Maintenance.java
+++ b/src/main/java/org/traccar/model/Maintenance.java
@@ -16,6 +16,9 @@
*/
package org.traccar.model;
+import org.traccar.storage.StorageName;
+
+@StorageName("tc_maintenances")
public class Maintenance extends ExtendedModel {
private String name;
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 f1983a03a..95e446132 100644
--- a/src/main/java/org/traccar/model/Notification.java
+++ b/src/main/java/org/traccar/model/Notification.java
@@ -18,10 +18,12 @@ package org.traccar.model;
import java.util.HashSet;
import java.util.Set;
-import org.traccar.database.QueryIgnore;
+import org.traccar.storage.QueryIgnore;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.traccar.storage.StorageName;
+@StorageName("tc_notifications")
public class Notification extends ScheduledModel {
private boolean always;
@@ -44,7 +46,6 @@ public class Notification extends ScheduledModel {
this.type = type;
}
-
private String notificators;
public String getNotificators() {
@@ -55,7 +56,6 @@ public class Notification extends ScheduledModel {
this.notificators = transports;
}
-
@JsonIgnore
@QueryIgnore
public Set<String> getNotificatorsTypes() {
diff --git a/src/main/java/org/traccar/model/Order.java b/src/main/java/org/traccar/model/Order.java
index fe6d926b8..7d09b0a47 100644
--- a/src/main/java/org/traccar/model/Order.java
+++ b/src/main/java/org/traccar/model/Order.java
@@ -15,6 +15,9 @@
*/
package org.traccar.model;
+import org.traccar.storage.StorageName;
+
+@StorageName("tc_orders")
public class Order extends ExtendedModel {
private String uniqueId;
diff --git a/src/main/java/org/traccar/model/Pair.java b/src/main/java/org/traccar/model/Pair.java
new file mode 100644
index 000000000..b679de57b
--- /dev/null
+++ b/src/main/java/org/traccar/model/Pair.java
@@ -0,0 +1,43 @@
+package org.traccar.model;
+
+import java.util.Objects;
+
+public class Pair<K, V> {
+
+ private final K first;
+ private final V second;
+
+ public Pair(K first, V second) {
+ this.first = first;
+ this.second = second;
+ }
+
+ public K getFirst() {
+ return first;
+ }
+
+ public V getSecond() {
+ return second;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Pair pair = (Pair) o;
+
+ return Objects.equals(first, pair.first) && Objects.equals(second, pair.second);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(first, second);
+ }
+
+}
diff --git a/src/main/java/org/traccar/model/Permission.java b/src/main/java/org/traccar/model/Permission.java
index 6475a4582..0b2f0584f 100644
--- a/src/main/java/org/traccar/model/Permission.java
+++ b/src/main/java/org/traccar/model/Permission.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,42 +16,121 @@
*/
package org.traccar.model;
-import java.util.Iterator;
+import java.beans.Introspector;
+import java.io.IOException;
+import java.net.URISyntaxException;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.TreeMap;
-import org.traccar.database.DataManager;
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.traccar.helper.ClassScanner;
+import org.traccar.storage.QueryIgnore;
public class Permission {
- private final Class<?> ownerClass;
+ 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(), (Class<? extends BaseModel>) clazz);
+ }
+ } catch (IOException | ReflectiveOperationException | URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private final LinkedHashMap<String, Long> data;
+
+ 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> permissionMap) throws ClassNotFoundException {
- Iterator<Map.Entry<String, Long>> iterator = permissionMap.entrySet().iterator();
- String owner = iterator.next().getKey();
- ownerClass = DataManager.getClassByName(owner);
- String property = iterator.next().getKey();
- propertyClass = DataManager.getClassByName(property);
- ownerId = permissionMap.get(owner);
- propertyId = permissionMap.get(property);
+ public Permission(LinkedHashMap<String, Long> data) {
+ this.data = data;
+ var iterator = data.entrySet().iterator();
+ var owner = iterator.next();
+ ownerClass = getKeyClass(owner.getKey());
+ ownerId = owner.getValue();
+ var property = iterator.next();
+ propertyClass = getKeyClass(property.getKey());
+ propertyId = property.getValue();
+ }
+
+ public Permission(
+ Class<? extends BaseModel> ownerClass, long ownerId,
+ Class<? extends BaseModel> propertyClass, long propertyId) {
+ this.ownerClass = ownerClass;
+ this.ownerId = ownerId;
+ this.propertyClass = propertyClass;
+ this.propertyId = propertyId;
+ data = new LinkedHashMap<>();
+ data.put(getKey(ownerClass), ownerId);
+ data.put(getKey(propertyClass), propertyId);
+ }
+
+ 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";
}
- public Class<?> getOwnerClass() {
+ public static String getStorageName(Class<?> ownerClass, Class<?> propertyClass) {
+ String ownerName = ownerClass.getSimpleName();
+ String propertyName = propertyClass.getSimpleName();
+ String managedPrefix = "Managed";
+ if (propertyName.startsWith(managedPrefix)) {
+ propertyName = propertyName.substring(managedPrefix.length());
+ }
+ return "tc_" + Introspector.decapitalize(ownerName) + "_" + Introspector.decapitalize(propertyName);
+ }
+
+ @QueryIgnore
+ @JsonIgnore
+ public String getStorageName() {
+ return getStorageName(ownerClass, propertyClass);
+ }
+
+ @QueryIgnore
+ @JsonAnyGetter
+ public Map<String, Long> get() {
+ return data;
+ }
+
+ @QueryIgnore
+ @JsonAnySetter
+ public void set(String key, Long value) {
+ data.put(key, value);
+ }
+
+ @QueryIgnore
+ @JsonIgnore
+ public Class<? extends BaseModel> getOwnerClass() {
return ownerClass;
}
+ @QueryIgnore
+ @JsonIgnore
public long getOwnerId() {
return ownerId;
}
- public Class<?> getPropertyClass() {
+ @QueryIgnore
+ @JsonIgnore
+ public Class<? extends BaseModel> getPropertyClass() {
return propertyClass;
}
+ @QueryIgnore
+ @JsonIgnore
public long getPropertyId() {
return propertyId;
}
+
}
diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java
index 09d25e832..1286db5f2 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.
@@ -17,8 +17,11 @@ package org.traccar.model;
import java.util.Date;
-import org.traccar.database.QueryIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.traccar.storage.QueryIgnore;
+import org.traccar.storage.StorageName;
+@StorageName("tc_positions")
public class Position extends Message {
public static final String KEY_ORIGINAL = "raw";
@@ -147,7 +150,6 @@ public class Position extends Message {
public Position(String protocol) {
this.protocol = protocol;
- this.serverTime = new Date();
}
private String protocol;
@@ -190,6 +192,7 @@ public class Position extends Message {
this.fixTime = fixTime;
}
+ @QueryIgnore
public void setTime(Date time) {
setDeviceTime(time);
setFixTime(time);
@@ -202,6 +205,7 @@ public class Position extends Message {
return outdated;
}
+ @QueryIgnore
public void setOutdated(boolean outdated) {
this.outdated = outdated;
}
@@ -223,6 +227,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;
}
@@ -233,6 +240,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;
}
@@ -296,10 +306,18 @@ public class Position extends Message {
this.network = network;
}
- @Override
+ @JsonIgnore
@QueryIgnore
+ @Override
public String getType() {
return super.getType();
}
+ @JsonIgnore
+ @QueryIgnore
+ @Override
+ public void setType(String type) {
+ super.setType(type);
+ }
+
}
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/Server.java b/src/main/java/org/traccar/model/Server.java
index 7bdb53b22..73645721b 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 - 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,11 +16,12 @@
package org.traccar.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import org.traccar.Context;
-import org.traccar.database.QueryIgnore;
+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;
@@ -34,6 +35,7 @@ public class Server extends ExtendedModel {
private boolean readonly;
+ @Override
public boolean getReadonly() {
return readonly;
}
@@ -44,6 +46,7 @@ public class Server extends ExtendedModel {
private boolean deviceReadonly;
+ @Override
public boolean getDeviceReadonly() {
return deviceReadonly;
}
@@ -82,6 +85,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() {
@@ -144,6 +157,7 @@ public class Server extends ExtendedModel {
private boolean limitCommands;
+ @Override
public boolean getLimitCommands() {
return limitCommands;
}
@@ -152,6 +166,28 @@ public class Server extends ExtendedModel {
this.limitCommands = limitCommands;
}
+ private boolean disableReports;
+
+ @Override
+ public boolean getDisableReports() {
+ return disableReports;
+ }
+
+ public void setDisableReports(boolean disableReports) {
+ 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() {
@@ -177,9 +213,52 @@ 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;
+
+ @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;
}
}
diff --git a/src/main/java/org/traccar/model/Statistics.java b/src/main/java/org/traccar/model/Statistics.java
index a9a117aef..0dc1b98e8 100644
--- a/src/main/java/org/traccar/model/Statistics.java
+++ b/src/main/java/org/traccar/model/Statistics.java
@@ -15,9 +15,12 @@
*/
package org.traccar.model;
+import org.traccar.storage.StorageName;
+
import java.util.Date;
import java.util.Map;
+@StorageName("tc_statistics")
public class Statistics extends ExtendedModel {
private Date captureTime;
diff --git a/src/main/java/org/traccar/model/User.java b/src/main/java/org/traccar/model/User.java
index 976b6aac0..53594fe07 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,13 +17,14 @@ package org.traccar.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
-import org.traccar.database.QueryExtended;
-import org.traccar.database.QueryIgnore;
+import org.traccar.storage.QueryIgnore;
import org.traccar.helper.Hashing;
+import org.traccar.storage.StorageName;
import java.util.Date;
-public class User extends ExtendedModel {
+@StorageName("tc_users")
+public class User extends ExtendedModel implements UserRestrictions, Disableable {
private String name;
@@ -67,6 +68,7 @@ public class User extends ExtendedModel {
private boolean readonly;
+ @Override
public boolean getReadonly() {
return readonly;
}
@@ -77,6 +79,12 @@ public class User extends ExtendedModel {
private boolean administrator;
+ @QueryIgnore
+ @JsonIgnore
+ public boolean getManager() {
+ return userLimit != 0;
+ }
+
public boolean getAdministrator() {
return administrator;
}
@@ -147,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;
}
@@ -187,6 +199,7 @@ public class User extends ExtendedModel {
private boolean deviceReadonly;
+ @Override
public boolean getDeviceReadonly() {
return deviceReadonly;
}
@@ -195,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;
}
@@ -222,6 +219,28 @@ public class User extends ExtendedModel {
this.limitCommands = limitCommands;
}
+ private boolean disableReports;
+
+ @Override
+ public boolean getDisableReports() {
+ return disableReports;
+ }
+
+ public void setDisableReports(boolean disableReports) {
+ 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() {
@@ -237,6 +256,7 @@ public class User extends ExtendedModel {
return null;
}
+ @QueryIgnore
public void setPassword(String password) {
if (password != null && !password.isEmpty()) {
Hashing.HashingResult hashingResult = Hashing.createHash(password);
@@ -248,11 +268,12 @@ public class User extends ExtendedModel {
private String hashedPassword;
@JsonIgnore
- @QueryExtended
+ @QueryIgnore
public String getHashedPassword() {
return hashedPassword;
}
+ @QueryIgnore
public void setHashedPassword(String hashedPassword) {
this.hashedPassword = hashedPassword;
}
@@ -260,11 +281,12 @@ public class User extends ExtendedModel {
private String salt;
@JsonIgnore
- @QueryExtended
+ @QueryIgnore
public String getSalt() {
return salt;
}
+ @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..9ee3b97b6 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 javax.inject.Inject;
+import javax.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..1d9f4f423 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 - 2022 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,71 @@
*/
package org.traccar.notification;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
+import com.google.inject.Injector;
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.Typed;
+import org.traccar.notificators.Notificator;
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 javax.inject.Inject;
+import javax.inject.Singleton;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Singleton
+public class NotificatorManager {
private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorManager.class);
- private static final Notificator NULL_NOTIFICATOR = new NotificatorNull();
+ private static final Map<String, Class<? extends Notificator>> NOTIFICATORS_ALL = Map.of(
+ "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) {
+ var notificator = injector.getInstance(clazz);
+ if (notificator != null) {
+ return notificator;
+ }
}
- return notificator;
+ LOGGER.warn("Failed to get notificator {}", type);
+ return new NotificatorNull();
}
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..444f4a7c2 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 javax.inject.Inject;
+import javax.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..052365c7a 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 - 2022 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,13 @@
*/
package org.traccar.notificators;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.traccar.model.Event;
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(User user, Event event, Position position) throws MessageException, InterruptedException;
}
diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java
index f91ec25a0..5ce2cbc0b 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 - 2022 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,91 @@
*/
package org.traccar.notificators;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
+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.MulticastMessage;
+import com.google.firebase.messaging.Notification;
+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.NotificationMessage;
+import org.traccar.notification.MessageException;
import org.traccar.notification.NotificationFormatter;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.InvocationCallback;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
-public class NotificatorFirebase extends Notificator {
+@Singleton
+public class NotificatorFirebase implements Notificator {
- private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorFirebase.class);
+ private final NotificationFormatter notificationFormatter;
- private final String url;
- private final String key;
+ @Inject
+ public NotificatorFirebase(Config config, NotificationFormatter notificationFormatter) throws IOException {
- public static class Notification {
- @JsonProperty("title")
- private String title;
- @JsonProperty("body")
- private String body;
- @JsonProperty("sound")
- private String sound;
- }
+ this.notificationFormatter = notificationFormatter;
- public static class Message {
- @JsonProperty("registration_ids")
- private String[] tokens;
- @JsonProperty("notification")
- private Notification notification;
- }
+ InputStream serviceAccount = new ByteArrayInputStream(
+ config.getString(Keys.NOTIFICATOR_FIREBASE_SERVICE_ACCOUNT).getBytes());
- public NotificatorFirebase() {
- this(
- "https://fcm.googleapis.com/fcm/send",
- Context.getConfig().getString(Keys.NOTIFICATOR_FIREBASE_KEY));
- }
+ FirebaseOptions options = FirebaseOptions.builder()
+ .setCredentials(GoogleCredentials.fromStream(serviceAccount))
+ .build();
- protected NotificatorFirebase(String url, String key) {
- this.url = url;
- this.key = key;
+ 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) {
- }
-
- @Override
- public void failed(Throwable throwable) {
- LOGGER.warn("Firebase notification error", throwable);
+ public void send(User user, Event event, Position position) throws MessageException {
+ if (user.hasAttribute("notificationTokens")) {
+
+ var shortMessage = notificationFormatter.formatMessage(user, event, position, "short");
+
+ List<String> registrationTokens = Arrays.asList(user.getString("notificationTokens").split("[, ]"));
+
+ MulticastMessage message = MulticastMessage.builder()
+ .setNotification(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);
+ for (var response : result.getResponses()) {
+ if (!response.isSuccessful()) {
+ throw new MessageException(response.getException());
+ }
}
- });
+ } catch (FirebaseMessagingException e) {
+ throw new MessageException(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..19fde6756 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 - 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,22 +16,34 @@
*/
package org.traccar.notificators;
-import org.traccar.Context;
+import org.traccar.mail.MailManager;
import org.traccar.model.Event;
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.inject.Inject;
+import javax.inject.Singleton;
import javax.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(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, 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
index 9364336be..ba9ade9c6 100644
--- a/src/main/java/org/traccar/notificators/NotificatorNull.java
+++ b/src/main/java/org/traccar/notificators/NotificatorNull.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,18 +20,14 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.model.Event;
import org.traccar.model.Position;
+import org.traccar.model.User;
-public final class NotificatorNull extends Notificator {
+public class NotificatorNull implements 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) {
+ public void send(User user, 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..e00db0579 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 - 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,22 +16,23 @@
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.Position;
import org.traccar.model.User;
import org.traccar.notification.NotificationFormatter;
-import org.traccar.notification.NotificationMessage;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.InvocationCallback;
-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 +51,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(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..e37d10888 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 - 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,37 +16,38 @@
*/
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.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 javax.inject.Inject;
+import javax.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(User user, Event event, Position position) throws MessageException, InterruptedException {
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..38e87c222 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 - 2022 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,23 @@
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.Position;
+import org.traccar.model.User;
import org.traccar.notification.NotificationFormatter;
-import org.traccar.notification.NotificationMessage;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.InvocationCallback;
-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 +62,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 +85,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(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 +94,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..9ae39f975 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 - 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,15 +15,69 @@
*/
package org.traccar.notificators;
-import org.traccar.Context;
+import com.fasterxml.jackson.annotation.JsonProperty;
+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;
-public class NotificatorTraccar extends NotificatorFirebase {
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.Entity;
- public NotificatorTraccar() {
- super(
- "https://www.traccar.org/push/",
- Context.getConfig().getString(Keys.NOTIFICATOR_TRACCAR_KEY));
+@Singleton
+public class NotificatorTraccar implements Notificator {
+
+ private final NotificationFormatter notificationFormatter;
+ private final Client client;
+
+ private final String url;
+ private final String key;
+
+ public static class Notification {
+ @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 Notification notification;
+ }
+
+ @Inject
+ public NotificatorTraccar(Config config, NotificationFormatter notificationFormatter, Client client) {
+ this.notificationFormatter = notificationFormatter;
+ this.client = client;
+ this.url = "https://www.traccar.org/push/";
+ this.key = config.getString(Keys.NOTIFICATOR_TRACCAR_KEY);
+ }
+
+ @Override
+ public void send(User user, Event event, Position position) {
+ if (user.hasAttribute("notificationTokens")) {
+
+ var shortMessage = notificationFormatter.formatMessage(user, 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;
+
+ client.target(url).request().header("Authorization", "key=" + key).post(Entity.json(message)).close();
+ }
}
}
diff --git a/src/main/java/org/traccar/notificators/NotificatorWeb.java b/src/main/java/org/traccar/notificators/NotificatorWeb.java
index 1d11c0b46..deabeade1 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 - 2022 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.Position;
+import org.traccar.model.User;
+import org.traccar.notification.NotificationFormatter;
+import org.traccar.session.ConnectionManager;
-public final class NotificatorWeb extends Notificator {
+import javax.inject.Inject;
+import javax.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(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..bab1d2339 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 javax.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..bc975c277 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 javax.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..b85b44382 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 javax.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..b0e974c69 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 javax.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..f1d6e659c 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 javax.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..47bb780cb 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 javax.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..25b2bf3b8 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 javax.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..6080df33d 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 javax.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..b33c2817f 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 javax.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..4f443aa3a 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 javax.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..39c6e8009 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 javax.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
new file mode 100644
index 000000000..32fba3b52
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/ArmoliProtocol.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.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 javax.inject.Inject;
+
+public class ArmoliProtocol extends BaseProtocol {
+
+ @Inject
+ public ArmoliProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ";;", ";\r", ";"));
+ pipeline.addLast(new StringEncoder());
+ pipeline.addLast(new StringDecoder());
+ pipeline.addLast(new ArmoliProtocolDecoder(ArmoliProtocol.this));
+ pipeline.addLast(new ArmoliProtocolPoller(ArmoliProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/ArmoliProtocolDecoder.java b/src/main/java/org/traccar/protocol/ArmoliProtocolDecoder.java
new file mode 100644
index 000000000..cbed64f76
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/ArmoliProtocolDecoder.java
@@ -0,0 +1,151 @@
+/*
+ * 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.session.DeviceSession;
+import org.traccar.NetworkMessage;
+import org.traccar.Protocol;
+import org.traccar.helper.ObdDecoder;
+import org.traccar.helper.Parser;
+import org.traccar.helper.PatternBuilder;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.util.regex.Pattern;
+
+public class ArmoliProtocolDecoder extends BaseProtocolDecoder {
+
+ public ArmoliProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("[M") // start
+ .number("(d{15})") // imei
+ .number("(dd)(dd)(dd)") // date (ddmmyy)
+ .number("(dd)(dd)(dd)") // time (hhmmss)
+ .number("([NS])(dd.d{6})") // latitude
+ .number("([EW])(ddd.d{6})") // longitude
+ .number("(d)") // valid
+ .number("(x)") // satellites
+ .number("(xx)") // speed
+ .number("(ddd)") // course
+ .number("(xxx)") // adc 1
+ .number("(xxx)") // adc 2
+ .number("(xx)") // status
+ .number("(xx)") // max speed
+ .number("(x{6})") // distance
+ .number("(dd)?") // hdop
+ .number("x{4}") // idle
+ .number(":(x+)").optional() // alarms
+ .number("G(x{6})").optional() // g-sensor
+ .number("H(x{3})").optional() // power
+ .number("E(x{3})").optional() // battery
+ .number("!(x+)").optional() // driver
+ .expression("@A([>0-9A-F]+)").optional() // obd
+ .any()
+ .compile();
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ String sentence = (String) msg;
+ char type = sentence.charAt(1);
+
+ Position position = new Position(getProtocolName());
+ DeviceSession deviceSession;
+
+ if (type != 'M') {
+ if (type == 'W') {
+ deviceSession = getDeviceSession(channel, remoteAddress);
+ if (deviceSession != null) {
+ position.setDeviceId(deviceSession.getDeviceId());
+ getLastLocation(position, null);
+ position.set(
+ Position.KEY_RESULT,
+ sentence.substring(sentence.indexOf(',') + 1, sentence.length() - 1));
+ return position;
+ }
+ } else if (channel != null && (type == 'Q' || type == 'L')) {
+ channel.writeAndFlush(new NetworkMessage("[TX,];;", remoteAddress));
+ }
+ return null;
+ }
+
+ Parser parser = new Parser(PATTERN, (String) msg);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ deviceSession = getDeviceSession(channel, remoteAddress, parser.next());
+ if (deviceSession == null) {
+ return null;
+ }
+
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.HEM_DEG));
+ position.setValid(parser.nextInt() > 0);
+
+ position.set(Position.KEY_SATELLITES, parser.nextHexInt());
+
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextHexInt()));
+ position.setCourse(parser.nextInt());
+
+ position.set(Position.PREFIX_ADC + 1, parser.nextHexInt() / 27.0 * 1000);
+ position.set(Position.PREFIX_ADC + 1, parser.nextHexInt() / 27.0 * 1000);
+ position.set(Position.KEY_STATUS, parser.nextHexInt());
+ position.set("maxSpeed", parser.nextHexInt());
+ position.set(Position.KEY_ODOMETER, parser.nextHexInt());
+
+ if (parser.hasNext()) {
+ position.set(Position.KEY_HDOP, parser.nextInt() * 0.1);
+ }
+ if (parser.hasNext()) {
+ position.set("alarms", parser.next());
+ }
+ if (parser.hasNext()) {
+ position.set(Position.KEY_G_SENSOR, parser.next());
+ }
+ if (parser.hasNext()) {
+ position.set(Position.KEY_POWER, parser.nextHexInt() * 0.01);
+ }
+ if (parser.hasNext()) {
+ position.set(Position.KEY_BATTERY, parser.nextHexInt() * 0.01);
+ }
+ if (parser.hasNext()) {
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next());
+ }
+ if (parser.hasNext()) {
+ String[] values = parser.next().split(">");
+ for (int i = 1; i < values.length; i++) {
+ String value = values[i];
+ position.add(ObdDecoder.decodeData(
+ Integer.parseInt(value.substring(4, 6), 16),
+ Long.parseLong(value.substring(6), 16), true));
+ }
+ }
+
+ return position;
+ }
+
+}
diff --git a/src/main/java/org/traccar/DeviceSession.java b/src/main/java/org/traccar/protocol/ArmoliProtocolPoller.java
index 322381807..f7bb9f593 100644
--- a/src/main/java/org/traccar/DeviceSession.java
+++ b/src/main/java/org/traccar/protocol/ArmoliProtocolPoller.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,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar;
+package org.traccar.protocol;
-import java.util.TimeZone;
+import io.netty.channel.Channel;
+import org.traccar.BaseProtocolPoller;
+import org.traccar.Protocol;
-public class DeviceSession {
+import java.net.SocketAddress;
- private final long deviceId;
+public class ArmoliProtocolPoller extends BaseProtocolPoller {
- public DeviceSession(long deviceId) {
- this.deviceId = deviceId;
+ public ArmoliProtocolPoller(Protocol protocol) {
+ super(180000);
}
- public long getDeviceId() {
- return deviceId;
- }
-
- private TimeZone timeZone;
-
- public void setTimeZone(TimeZone timeZone) {
- this.timeZone = timeZone;
- }
-
- public TimeZone getTimeZone() {
- return timeZone;
+ @Override
+ protected void sendRequest(Channel channel, SocketAddress remoteAddress) {
+ channel.writeAndFlush("[TX,];;");
}
}
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..091d5c06f 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 javax.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..361eeeef2 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 javax.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..021a81e07 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 javax.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..25e9be86f 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 javax.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..21eb09696 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 javax.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..340641729 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);
@@ -524,20 +526,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 +632,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..d37884c8b 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 javax.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..6a68467e2 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 javax.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..0566b1da6 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 javax.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..bc80e473a 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 javax.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..80255d3e9 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 javax.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..b35a447ff 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 javax.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..c4a0affdc 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 javax.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..582be0b56 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 javax.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..635806b2d 100644
--- a/src/main/java/org/traccar/protocol/B2316ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/B2316ProtocolDecoder.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.model.CellTower;
import org.traccar.model.Network;
@@ -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..31fb1bd83 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 javax.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 c1a69981d..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;
@@ -90,11 +90,13 @@ public class BceProtocolDecoder extends BaseProtocolDecoder {
}
if (BitUtil.check(mask, 14)) {
- position.setNetwork(new Network(CellTower.from(
- buf.readUnsignedShortLE(), buf.readUnsignedByte(),
- buf.readUnsignedShortLE(), buf.readUnsignedShortLE(),
- buf.readUnsignedByte())));
- buf.readUnsignedByte();
+ int mcc = buf.readUnsignedShortLE();
+ int mnc = buf.readUnsignedByte();
+ int lac = buf.readUnsignedShortLE();
+ int cid = buf.readUnsignedShortLE();
+ buf.readUnsignedByte(); // time advance
+ int rssi = -buf.readUnsignedByte();
+ position.setNetwork(new Network(CellTower.from(mcc, mnc, lac, cid, rssi)));
}
}
diff --git a/src/main/java/org/traccar/protocol/BlackKiteProtocol.java b/src/main/java/org/traccar/protocol/BlackKiteProtocol.java
index 617a24d7a..3859a9273 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 javax.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..da195f438 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 javax.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..dc6852d50 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 javax.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..dde14a2ca
--- /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 javax.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..5cd8ef4fd 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 javax.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 83e62ff86..aef158fc7 100644
--- a/src/main/java/org/traccar/protocol/C2stekProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/C2stekProtocolDecoder.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,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();
@@ -111,9 +113,13 @@ public class C2stekProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001);
position.set(Position.KEY_ALARM, decodeAlarm(parser.nextHexInt()));
- 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()) {
+ position.set(Position.KEY_ARMED, 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..d67308cf2 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 javax.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..0538aad72 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 javax.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..832d9bb2d 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 javax.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..a4413af28 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 javax.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..9323b1503 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 javax.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..4aa65245b 100644
--- a/src/main/java/org/traccar/protocol/CastelProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/CastelProtocolDecoder.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;
@@ -160,6 +160,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();
@@ -443,7 +446,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 +502,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..d0ca35ef1 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 javax.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..3287928c7 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 javax.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..caf0aad42 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 javax.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..9656b284b 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 javax.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..06e93d79d 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 javax.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..7f201a31d 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 javax.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..e9466b7e8 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 javax.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..f83b8349a 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 javax.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..0dab26cda 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 javax.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 15cf84a5f..807850778 100644
--- a/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/DmtHttpProtocolDecoder.java
@@ -19,7 +19,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.BitUtil;
import org.traccar.helper.UnitsConverter;
@@ -174,21 +174,25 @@ public class DmtHttpProtocolDecoder extends BaseHttpProtocolDecoder {
position.set(Position.KEY_INDEX, root.getInt("sqn"));
position.set(Position.KEY_EVENT, root.getInt("reason"));
- JsonArray analogues = root.getJsonArray("analogues");
- for (int i = 0; i < analogues.size(); i++) {
- JsonObject adc = analogues.getJsonObject(i);
- position.set(Position.PREFIX_ADC + adc.getInt("id"), adc.getInt("val"));
+ if (root.containsKey("analogues")) {
+ JsonArray analogues = root.getJsonArray("analogues");
+ for (int i = 0; i < analogues.size(); i++) {
+ JsonObject adc = analogues.getJsonObject(i);
+ position.set(Position.PREFIX_ADC + adc.getInt("id"), adc.getInt("val"));
+ }
}
- int input = root.getInt("inputs");
- int output = root.getInt("outputs");
- int status = root.getInt("status");
-
- position.set(Position.KEY_IGNITION, BitUtil.check(input, 0));
-
- position.set(Position.KEY_INPUT, input);
- position.set(Position.KEY_OUTPUT, output);
- position.set(Position.KEY_STATUS, status);
+ if (root.containsKey("inputs")) {
+ int input = root.getInt("inputs");
+ position.set(Position.KEY_IGNITION, BitUtil.check(input, 0));
+ position.set(Position.KEY_INPUT, input);
+ }
+ if (root.containsKey("outputs")) {
+ position.set(Position.KEY_OUTPUT, root.getInt("outputs"));
+ }
+ if (root.containsKey("status")) {
+ position.set(Position.KEY_STATUS, root.getInt("status"));
+ }
if (root.containsKey("counters")) {
JsonArray counters = root.getJsonArray("counters");
diff --git a/src/main/java/org/traccar/protocol/DmtProtocol.java b/src/main/java/org/traccar/protocol/DmtProtocol.java
index 78a5243c0..de56c9372 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 javax.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..ed627be78 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 javax.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/Dsf22FrameDecoder.java b/src/main/java/org/traccar/protocol/Dsf22FrameDecoder.java
new file mode 100644
index 000000000..388c97f85
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/Dsf22FrameDecoder.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 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.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import org.traccar.BaseFrameDecoder;
+
+public class Dsf22FrameDecoder extends BaseFrameDecoder {
+
+ @Override
+ protected Object decode(
+ ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception {
+
+ if (buf.readableBytes() < 21) {
+ return null;
+ }
+
+ int count = buf.getUnsignedByte(buf.readerIndex() + 4);
+
+ int length = 2 + 2 + 1 + count * (4 + 4 + 4 + 1 + 2 + 1);
+
+ if (buf.readableBytes() >= length) {
+ return buf.readRetainedSlice(length);
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/Dsf22Protocol.java b/src/main/java/org/traccar/protocol/Dsf22Protocol.java
new file mode 100644
index 000000000..06c99b0f9
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/Dsf22Protocol.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 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.protocol;
+
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+import org.traccar.config.Config;
+
+import javax.inject.Inject;
+
+public class Dsf22Protocol extends BaseProtocol {
+
+ @Inject
+ public Dsf22Protocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new Dsf22FrameDecoder());
+ pipeline.addLast(new Dsf22ProtocolDecoder(Dsf22Protocol.this));
+ }
+ });
+ addServer(new TrackerServer(config, getName(), true) {
+ @Override
+ 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
new file mode 100644
index 000000000..124bbfefa
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/Dsf22ProtocolDecoder.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ * 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.session.DeviceSession;
+import org.traccar.NetworkMessage;
+import org.traccar.Protocol;
+import org.traccar.helper.BitUtil;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+public class Dsf22ProtocolDecoder extends BaseProtocolDecoder {
+
+ public Dsf22ProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ByteBuf buf = (ByteBuf) msg;
+
+ buf.skipBytes(2); // header
+
+ String id = String.valueOf(buf.readUnsignedShortLE());
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ 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());
+
+ position.setValid(true);
+ position.setLatitude(buf.readIntLE() / 10000000.0);
+ position.setLongitude(buf.readIntLE() / 10000000.0);
+ position.setTime(new Date(buf.readUnsignedIntLE() * 1000));
+ position.setSpeed(UnitsConverter.knotsFromKph(buf.readUnsignedByte()));
+
+ position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedShortLE() * 0.001);
+
+ int status = buf.readUnsignedByte();
+ position.set(Position.KEY_IGNITION, BitUtil.check(status, 0));
+ position.set(Position.PREFIX_IN + 1, BitUtil.check(status, 1));
+ position.set(Position.PREFIX_OUT + 1, BitUtil.check(status, 4));
+ position.set(Position.KEY_ALARM, BitUtil.check(status, 6) ? Position.ALARM_JAMMING : null);
+ position.set(Position.KEY_STATUS, status);
+
+ positions.add(position);
+
+ }
+
+ if (channel != null) {
+ byte[] response = {0x01};
+ channel.writeAndFlush(new NetworkMessage(Unpooled.wrappedBuffer(response), remoteAddress));
+ }
+
+ return positions;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/DualcamProtocol.java b/src/main/java/org/traccar/protocol/DualcamProtocol.java
index 04c4f2bd1..363a2c5d9 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 javax.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..1096c945c 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 javax.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..39aa61580 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 javax.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..35fd4fe65 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 javax.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 068b19cbc..941b10fef 100644
--- a/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/EelinkProtocolDecoder.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.
@@ -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;
@@ -31,6 +31,7 @@ import org.traccar.helper.UnitsConverter;
import org.traccar.model.CellTower;
import org.traccar.model.Network;
import org.traccar.model.Position;
+import org.traccar.model.WifiAccessPoint;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
@@ -192,30 +193,67 @@ public class EelinkProtocolDecoder extends BaseProtocolDecoder {
getLastLocation(position, position.getDeviceTime());
}
+ Network network = new Network();
+
+ int mcc = 0;
+ int mnc = 0;
if (BitUtil.check(flags, 1)) {
- position.setNetwork(new Network(CellTower.from(
- buf.readUnsignedShort(), buf.readUnsignedShort(),
- buf.readUnsignedShort(), buf.readUnsignedInt(), buf.readUnsignedByte())));
+ mcc = buf.readUnsignedShort();
+ mnc = buf.readUnsignedShort();
+ network.addCellTower(CellTower.from(
+ mcc, mnc, buf.readUnsignedShort(), buf.readUnsignedInt(), buf.readUnsignedByte()));
}
if (BitUtil.check(flags, 2)) {
- buf.skipBytes(7); // bsid1
+ network.addCellTower(CellTower.from(
+ mcc, mnc, buf.readUnsignedShort(), buf.readUnsignedInt(), buf.readUnsignedByte()));
}
if (BitUtil.check(flags, 3)) {
- buf.skipBytes(7); // bsid2
+ network.addCellTower(CellTower.from(
+ mcc, mnc, buf.readUnsignedShort(), buf.readUnsignedInt(), buf.readUnsignedByte()));
}
if (BitUtil.check(flags, 4)) {
- buf.skipBytes(7); // bss0
+ String mac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:");
+ network.addWifiAccessPoint(WifiAccessPoint.from(
+ mac.substring(0, mac.length() - 1), buf.readUnsignedByte()));
}
if (BitUtil.check(flags, 5)) {
- buf.skipBytes(7); // bss1
+ String mac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:");
+ network.addWifiAccessPoint(WifiAccessPoint.from(
+ mac.substring(0, mac.length() - 1), buf.readUnsignedByte()));
}
if (BitUtil.check(flags, 6)) {
- buf.skipBytes(7); // bss2
+ String mac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:");
+ network.addWifiAccessPoint(WifiAccessPoint.from(
+ mac.substring(0, mac.length() - 1), buf.readUnsignedByte()));
+ }
+
+ if (BitUtil.check(flags, 7)) {
+ buf.readUnsignedByte(); // radio access technology
+ int count = buf.readUnsignedByte();
+ int lac = 0;
+ if (count > 0) {
+ mcc = buf.readUnsignedShort();
+ mnc = buf.readUnsignedShort();
+ lac = buf.readUnsignedShort(); // lac
+ buf.readUnsignedShort(); // tac
+ buf.readUnsignedInt(); // cid
+ buf.readUnsignedShort(); // ta
+ }
+ for (int i = 0; i < count; i++) {
+ int cid = buf.readUnsignedShort(); // physical cid
+ buf.readUnsignedShort(); // e-arfcn
+ int rssi = buf.readUnsignedByte();
+ network.addCellTower(CellTower.from(mcc, mnc, lac, cid, rssi));
+ }
+ }
+
+ if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) {
+ position.setNetwork(network);
}
if (type == MSG_WARNING) {
diff --git a/src/main/java/org/traccar/protocol/EgtsProtocol.java b/src/main/java/org/traccar/protocol/EgtsProtocol.java
index 5d4638f37..f257271d4 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 javax.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..ebde56f70 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 javax.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..e326481fa 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 javax.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
new file mode 100644
index 000000000..dffa1c991
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/EnvotechProtocol.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 javax.inject.Inject;
+
+public class EnvotechProtocol extends BaseProtocol {
+
+ @Inject
+ public EnvotechProtocol(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 EnvotechProtocolDecoder(EnvotechProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/EnvotechProtocolDecoder.java b/src/main/java/org/traccar/protocol/EnvotechProtocolDecoder.java
new file mode 100644
index 000000000..750ff2bda
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/EnvotechProtocolDecoder.java
@@ -0,0 +1,116 @@
+/*
+ * 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.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.regex.Pattern;
+
+public class EnvotechProtocolDecoder extends BaseProtocolDecoder {
+
+ public EnvotechProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("$")
+ .number("dd") // mode
+ .expression("...,") // hardware
+ .number("(x+),") // event
+ .number("x+,") // group
+ .number("(x+),") // device id
+ .number("(dd)(dd)(dd)") // date (ddmmyy)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .number("xx") // connection status
+ .number("(dd)") // rssi
+ .number("d{5},") // mcc
+ .number("(ddd)") // power
+ .number("(ddd),") // battery
+ .number("(xx)") // inputs
+ .number("(xx),") // outputs
+ .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("(d+)(d{5})([NS])") // latitude
+ .number("(d+)(d{5})([EW])") // longitude
+ .number("(ddd)") // speed
+ .number("(ddd)") // course
+ .any()
+ .compile();
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ Parser parser = new Parser(PATTERN, (String) msg);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+
+ 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) {
+ return null;
+ }
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setDeviceTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+
+ position.set(Position.KEY_RSSI, parser.nextInt());
+ position.set(Position.KEY_POWER, parser.nextInt() * 0.01);
+ position.set(Position.KEY_BATTERY, parser.nextInt() * 0.01);
+ position.set(Position.KEY_INPUT, parser.nextHexInt());
+ position.set(Position.PREFIX_OUT, parser.nextHexInt());
+ position.set(Position.KEY_FUEL_LEVEL, 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_DEG_HEM));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_DEG_HEM));
+ position.setSpeed(parser.nextInt());
+ position.setCourse(parser.nextInt());
+
+ return position;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/EsealProtocol.java b/src/main/java/org/traccar/protocol/EsealProtocol.java
index fc1d342e1..0ed80dc6f 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 javax.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..cb2f59dc8 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 javax.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..ffc941b69 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 javax.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..fd2beaabb 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 javax.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..a9d77b46e 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 {
@@ -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());
@@ -244,6 +254,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;
}
@@ -381,7 +396,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..374cf77e2 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 javax.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..6e6f9c700 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,7 +19,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.UnitsConverter;
import org.traccar.model.Position;
@@ -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;
}
@@ -228,6 +228,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
new file mode 100644
index 000000000..088072d2d
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/FlexApiProtocol.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 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.protocol;
+
+import io.netty.handler.codec.LineBasedFrameDecoder;
+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 javax.inject.Inject;
+
+public class FlexApiProtocol extends BaseProtocol {
+
+ @Inject
+ public FlexApiProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
+ @Override
+ 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
new file mode 100644
index 000000000..2dec44e64
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ * 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.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 java.io.StringReader;
+import java.net.SocketAddress;
+import java.util.Date;
+
+public class FlexApiProtocolDecoder extends BaseProtocolDecoder {
+
+ public FlexApiProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ String message = (String) msg;
+ JsonObject root = Json.createReader(new StringReader(message.substring(1, message.length() - 2))).readObject();
+
+ String topic = root.getString("topic");
+ String clientId = topic.substring(3, topic.indexOf('/', 3));
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, clientId);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ JsonObject payload = root.getJsonObject("payload");
+
+ if (topic.contains("/gnss/")) {
+
+ position.setValid(true);
+
+ if (payload.containsKey("time")) {
+ position.setTime(new Date(payload.getInt("time") * 1000L));
+ position.setLatitude(payload.getJsonNumber("lat").doubleValue());
+ position.setLongitude(payload.getJsonNumber("log").doubleValue());
+ } else {
+ position.setTime(new Date(payload.getInt("gnss.ts") * 1000L));
+ position.setLatitude(payload.getJsonNumber("gnss.latitude").doubleValue());
+ position.setLongitude(payload.getJsonNumber("gnss.longitude").doubleValue());
+ }
+
+ position.setValid(payload.getInt("gnss.fix") > 0);
+ position.setAltitude(payload.getJsonNumber("gnss.altitude").doubleValue());
+ position.setSpeed(payload.getJsonNumber("gnss.speed").doubleValue());
+ position.setCourse(payload.getJsonNumber("gnss.heading").doubleValue());
+
+ position.set(Position.KEY_SATELLITES, payload.getInt("gnss.num_sv"));
+ position.set(Position.KEY_HDOP, payload.getJsonNumber("gnss.hdop").doubleValue());
+
+ } else if (topic.contains("/cellular1/")) {
+
+ getLastLocation(position, new Date(payload.getInt("modem1.ts") * 1000L));
+
+ position.set("imei", payload.getString("modem1.imei"));
+ position.set("imsi", payload.getString("modem1.imsi"));
+ position.set(Position.KEY_ICCID, payload.getString("modem1.iccid"));
+
+ String operator = payload.getString("modem1.operator");
+ if (!operator.isEmpty()) {
+ CellTower cellTower = CellTower.from(
+ Integer.parseInt(operator.substring(0, 3)),
+ Integer.parseInt(operator.substring(3)),
+ Integer.parseInt(payload.getString("modem1.lac"), 16),
+ Integer.parseInt(payload.getString("modem1.cell_id"), 16),
+ payload.getInt("modem1.rssi"));
+ switch (payload.getInt("modem1.network")) {
+ case 1:
+ cellTower.setRadioType("gsm");
+ break;
+ case 2:
+ cellTower.setRadioType("wcdma");
+ break;
+ case 3:
+ cellTower.setRadioType("lte");
+ break;
+ default:
+ break;
+ }
+ position.setNetwork(new Network(cellTower));
+ }
+
+ } else if (topic.contains("/obd/")) {
+
+ getLastLocation(position, new Date(payload.getInt("obd.ts") * 1000L));
+
+ if (payload.containsKey("obd.speed")) {
+ position.set(Position.KEY_OBD_SPEED, payload.getJsonNumber("obd.speed").doubleValue());
+ }
+ if (payload.containsKey("obd.odo")) {
+ position.set(Position.KEY_OBD_ODOMETER, payload.getInt("obd.odo"));
+ }
+ if (payload.containsKey("obd.rpm")) {
+ position.set(Position.KEY_RPM, payload.getInt("obd.rpm"));
+ }
+ if (payload.containsKey("obd.vin")) {
+ position.set(Position.KEY_VIN, payload.getString("obd.vin"));
+ }
+
+ } else if (topic.contains("/motion/")) {
+
+ getLastLocation(position, new Date(payload.getInt("motion.ts") * 1000L));
+
+ position.set("ax", payload.getJsonNumber("motion.ax").doubleValue());
+ position.set("ay", payload.getJsonNumber("motion.ay").doubleValue());
+ position.set("az", payload.getJsonNumber("motion.az").doubleValue());
+ position.set("gx", payload.getJsonNumber("motion.gx").doubleValue());
+ position.set("gy", payload.getJsonNumber("motion.gy").doubleValue());
+ position.set("gz", payload.getJsonNumber("motion.gz").doubleValue());
+
+ } else if (topic.contains("/io/")) {
+
+ getLastLocation(position, new Date(payload.getInt("io.ts") * 1000L));
+
+ if (payload.containsKey("io.IGT")) {
+ position.set(Position.KEY_IGNITION, payload.getInt("io.IGT") > 0);
+ }
+
+ for (String key : payload.keySet()) {
+ if (key.startsWith("io.AI")) {
+ position.set(Position.PREFIX_ADC + key.substring(5), payload.getJsonNumber(key).doubleValue());
+ } else if (key.startsWith("io.DI") && !key.endsWith("_pullup")) {
+ position.set(Position.PREFIX_IN + key.substring(5), payload.getInt(key) > 0);
+ } else if (key.startsWith("io.DO")) {
+ position.set(Position.PREFIX_OUT + key.substring(5), payload.getInt(key) > 0);
+ }
+ }
+
+ } else if (topic.contains("/sysinfo/")) {
+
+ getLastLocation(position, new Date(payload.getInt("sysinfo.ts") * 1000L));
+
+ position.set("serial", payload.getString("sysinfo.serial_number"));
+ position.set(Position.KEY_VERSION_FW, payload.getString("sysinfo.firmware_version"));
+
+ } else {
+
+ return null;
+
+ }
+
+ return position;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/FlexCommProtocol.java b/src/main/java/org/traccar/protocol/FlexCommProtocol.java
index 9343ebeb8..5397156cb 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 javax.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..61e315af9 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 javax.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..ebac8b4de 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 javax.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..fa45b3817 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 javax.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..dac117c04 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 javax.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..dce4994ab 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 javax.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..4e5200f37 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;
diff --git a/src/main/java/org/traccar/protocol/FutureWayProtocol.java b/src/main/java/org/traccar/protocol/FutureWayProtocol.java
index 73b53ee12..715dd3c9c 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 javax.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..f1823762d
--- /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 javax.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/GalileoProtocol.java b/src/main/java/org/traccar/protocol/GalileoProtocol.java
index a1570c9b0..90e95574a 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 javax.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..fc8a49cf5 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 - 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,15 +20,16 @@ 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.helper.BitBuffer;
import org.traccar.helper.UnitsConverter;
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 +37,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 {
@@ -215,7 +217,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,7 +232,11 @@ 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);
}
@@ -239,10 +244,58 @@ public class GalileoProtocolDecoder extends BaseProtocolDecoder {
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(360 * 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.readUnsignedShortLE(); // length
+
+ buf.skipBytes(3); // identification header
+ buf.readUnsignedIntLE(); // index
+
+ 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
+ buf.readUnsignedIntLE(); // date and time
+
+ buf.skipBytes(23); // coordinates block
+
+ buf.skipBytes(3); // data tag header
+ decodeMinimalDataSet(position, buf);
+
+ return position;
+ }
+
+ private List<Position> decodePositions(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
- int length = (buf.readUnsignedShortLE() & 0x7fff) + 3;
+ int endIndex = (buf.readUnsignedShortLE() & 0x7fff) + buf.readerIndex();
List<Position> positions = new LinkedList<>();
Set<Integer> tags = new HashSet<>();
@@ -251,7 +304,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 +340,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 +375,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;
diff --git a/src/main/java/org/traccar/protocol/GatorProtocol.java b/src/main/java/org/traccar/protocol/GatorProtocol.java
index ca81caefb..7341b69a3 100644
--- a/src/main/java/org/traccar/protocol/GatorProtocol.java
+++ b/src/main/java/org/traccar/protocol/GatorProtocol.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 javax.inject.Inject;
public class GatorProtocol extends BaseProtocol {
- public GatorProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public GatorProtocol(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 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..644caee81 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;
diff --git a/src/main/java/org/traccar/protocol/GenxProtocol.java b/src/main/java/org/traccar/protocol/GenxProtocol.java
index c87ba946a..97d8633a0 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 javax.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..e1748c9a0 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 javax.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..c7b6a8e7c 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 javax.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..a9736c9e7 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 javax.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 683ba476e..517499f02 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 - 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,8 +16,7 @@
package org.traccar.protocol;
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;
@@ -46,11 +45,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()
@@ -139,7 +142,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
.number("(x+)?,") // lac
.number("(x+)?,") // cid
.groupEnd()
- .number("(?:d+|(d+.d))?,") // odometer
+ .number("(?:d+|(d+.d))?,") // rssi / odometer
.compile();
private static final Pattern PATTERN_OBD = new PatternBuilder()
@@ -184,7 +187,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
.expression("(?:([0-9A-Z]{17}),)?") // vin
.expression("[^,]*,") // device name
.number("(d+)?,") // power
- .number("d{1,2},").optional() // report type
+ .number("(d{1,2}),").optional() // report type
.number("d{1,2},").optional() // count
.number("d*,").optional() // reserved
.number("(d+),").optional() // battery
@@ -208,11 +211,11 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
.number("(?:d+.?d*|Inf|NaN)?,") // fuel consumption
.number("(d+)?,") // fuel level
.or()
- .number("(d{1,7}.d)?,").optional() // odometer
- .number("(d{1,3})?,") // battery
- .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)
@@ -349,6 +352,22 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
.text("$").optional()
.compile();
+ 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 static final Pattern PATTERN = new PatternBuilder()
.text("+").expression("(?:RESP|BUFF):GT...,")
.number("(?:[0-9A-Z]{2}xxxx)?,") // protocol version
@@ -357,15 +376,16 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
.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)?,").optional() // odometer
+ .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)
+ .number("(dd)(dd)(dd)") // time (hhmmss)
.text(",")
.number("(xxxx)") // count number
.text("$").optional()
@@ -377,6 +397,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
.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
@@ -835,6 +856,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
String vin = parser.next();
Integer power = parser.nextInt();
+ Integer reportType = parser.nextInt();
Integer battery = parser.nextInt();
Parser itemParser = new Parser(PATTERN_LOCATION, parser.next());
@@ -877,12 +899,18 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_RPM, parser.nextInt());
position.set(Position.KEY_FUEL_LEVEL, parser.nextInt());
+ if (parser.hasNext(2)) {
+ if (reportType != null) {
+ position.set(Position.KEY_MOTION, BitUtil.check(reportType, 0));
+ position.set(Position.KEY_CHARGE, BitUtil.check(reportType, 1));
+ }
+ position.set(Position.KEY_RSSI, parser.nextInt());
+ position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
+ }
if (parser.hasNext()) {
position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000);
}
position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
- position.set(Position.KEY_RSSI, parser.nextInt());
- position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
decodeDeviceTime(position, parser);
if (ignoreFixTime) {
@@ -1114,6 +1142,29 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ 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 Object decodeOther(Channel channel, SocketAddress remoteAddress, String sentence, String type) {
Parser parser = new Parser(PATTERN, sentence);
Position position = initPosition(parser, channel, remoteAddress);
@@ -1305,6 +1356,9 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
case "PFA":
result = decodePna(channel, remoteAddress, sentence);
break;
+ case "DAR":
+ result = decodeDar(channel, remoteAddress, sentence);
+ break;
default:
result = decodeOther(channel, remoteAddress, sentence, type);
break;
@@ -1325,7 +1379,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..16b99f426 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 javax.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..293f5fda5 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 javax.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..32d642688 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 javax.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..607931500 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 javax.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..77649a041 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;
diff --git a/src/main/java/org/traccar/protocol/GotopProtocol.java b/src/main/java/org/traccar/protocol/GotopProtocol.java
index 07fe02248..53fcea0d0 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 javax.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..dbffbfdbb 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 javax.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..2725494c5 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 javax.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..28efa3c30 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.hasNext(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..a6a73ae6b 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 javax.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..12b53342c 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 javax.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..a474b1e53 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 javax.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..bb66501e2 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 javax.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..425ca9330 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 javax.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..fa05761f6 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 javax.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..38278121c 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 javax.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 0dcdab892..ef09677bf 100644
--- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.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.
@@ -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.helper.BcdUtil;
@@ -32,7 +31,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;
@@ -70,19 +68,20 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_GPS_LBS_STATUS_3 = 0x27;
public static final int MSG_LBS_MULTIPLE_1 = 0x28;
public static final int MSG_LBS_MULTIPLE_2 = 0x2E;
+ public static final int MSG_LBS_MULTIPLE_3 = 0x24;
public static final int MSG_LBS_WIFI = 0x2C;
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
+ public static final int MSG_GPS_LBS_STATUS_4 = 0x32; // AZ735
+ public static final int MSG_WIFI_5 = 0x33; // AZ735
+ public static final int MSG_AZ735_GPS = 0x32; // AZ735 / only 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;
@@ -92,25 +91,63 @@ 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_2 = 0xA0; // GK310
+ 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
+ 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,
+ }
+
+ 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);
@@ -172,6 +209,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_LBS_ALARM:
return true;
default:
return false;
@@ -297,9 +335,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) {
+ lac = buf.readInt();
+ } else {
+ lac = buf.readUnsignedShort();
+ }
+ long cid;
+ if (type == MSG_LBS_ALARM) {
+ 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)));
@@ -310,7 +365,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();
@@ -332,22 +387,19 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
case 4:
position.set(Position.KEY_ALARM, Position.ALARM_SOS);
break;
+ case 6:
+ position.set(Position.KEY_ALARM, Position.ALARM_GEOFENCE);
+ break;
case 7:
- position.set(Position.KEY_ALARM, Position.ALARM_REMOVING);
+ if (variant == Variant.VXT01) {
+ position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED);
+ } else {
+ position.set(Position.KEY_ALARM, Position.ALARM_REMOVING);
+ }
break;
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());
- position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
-
- return true;
}
private String decodeAlarm(short value) {
@@ -367,13 +419,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:
@@ -383,81 +442,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) throws Exception {
+ 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()));
}
}
@@ -467,8 +472,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) {
@@ -480,23 +485,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);
@@ -525,6 +528,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"));
@@ -537,44 +542,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) {
buf.readUnsignedInt(); // data and alarm
- decodeGps(position, buf, false, deviceSession.getTimeZone());
+ decodeGps(position, buf, false, deviceSession.get(DeviceSession.KEY_TIMEZONE));
buf.readUnsignedShort(); // terminal info
@@ -618,103 +592,111 @@ 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;
+
+ } else if (type == MSG_LBS_MULTIPLE_3 && variant == Variant.SR411_MINI) {
+
+ decodeGps(position, buf, false, deviceSession.get(DeviceSession.KEY_TIMEZONE));
- if (type == MSG_LBS_STATUS && dataLength >= 18) {
+ decodeLbs(position, buf, type, false);
- return null; // space10x multi-lbs message
+ 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_EXTEND
- || type == MSG_LBS_WIFI || type == MSG_LBS_2 || type == MSG_WIFI_3 || type == MSG_WIFI_5) {
+ } 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_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());
+ if (variant == Variant.WANWAY_S20) {
+ buf.readUnsignedByte(); // ta
+ }
+
int mcc = buf.readUnsignedShort();
int mnc = BitUtil.check(mcc, 15) ? buf.readUnsignedShort() : buf.readUnsignedByte();
Network network = new Network();
- int cellCount = 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();
@@ -724,9 +706,12 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
}
}
- buf.readUnsignedByte(); // time leads
+ if (variant != Variant.WANWAY_S20) {
+ buf.readUnsignedByte(); // ta
+ }
- if (type != MSG_LBS_MULTIPLE_1 && type != MSG_LBS_MULTIPLE_2 && type != MSG_LBS_2) {
+ if (type != MSG_LBS_MULTIPLE_1 && type != MSG_LBS_MULTIPLE_2 && type != MSG_LBS_MULTIPLE_3
+ && type != MSG_LBS_2) {
int wifiCount = buf.readUnsignedByte();
for (int i = 0; i < wifiCount; i++) {
String mac = ByteBufUtil.hexDump(buf.readSlice(6)).replaceAll("(..)", "$1:");
@@ -753,7 +738,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
@@ -785,20 +770,144 @@ 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) {
+ decodeLbs(position, buf, type, hasStatus(type) && type != MSG_LBS_ALARM);
+ }
+
+ 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());
+ position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
+ }
+ }
+
+ 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("driverLicense", 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);
+ }
+ }
+
+ 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() == 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());
+ decodeGps(position, buf, false, false, false, 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());
@@ -830,6 +939,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
break;
}
+
} else {
if (dataLength > 0) {
@@ -855,114 +965,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);
- }
-
- if (type == MSG_GPS_LBS_1 && 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());
- }
-
- if (type == MSG_GPS_LBS_1 && buf.readableBytes() == 18) {
- decodeStatus(position, buf, false);
- 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_1 && buf.readableBytes() == 2 + 6) {
- 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);
- }
- }
- }
-
- 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);
@@ -970,8 +972,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());
@@ -990,7 +992,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);
}
@@ -1004,31 +1015,62 @@ 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 == 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) {
@@ -1043,15 +1085,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());
}
@@ -1096,7 +1136,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());
@@ -1143,132 +1183,111 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
} else if (type == MSG_GPS_MODULAR) {
- return decodeExtendedModular(channel, buf, deviceSession);
-
- } 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));
+ while (buf.readableBytes() > 6) {
+ int moduleType = buf.readUnsignedShort();
+ int moduleLength = buf.readUnsignedShort();
- 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;
@@ -1301,9 +1320,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();
}
}
@@ -1343,21 +1360,56 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder {
return null;
}
+ private void decodeVariant(ByteBuf buf) {
+ int header = buf.getUnsignedShort(buf.readerIndex());
+ int length;
+ int type;
+ if (header == 0x7878) {
+ length = buf.getUnsignedByte(buf.readerIndex() + 2);
+ type = buf.getUnsignedByte(buf.readerIndex() + 2 + 1);
+ } else {
+ length = buf.getUnsignedShort(buf.readerIndex() + 2);
+ type = buf.getUnsignedByte(buf.readerIndex() + 2 + 2);
+ }
+
+ if (header == 0x7878 && type == MSG_GPS_LBS_1 && length == 0x24) {
+ 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 {
+ variant = Variant.STANDARD;
+ }
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
+ decodeVariant(buf);
+
int header = buf.readShort();
if (header == 0x7878) {
return decodeBasic(channel, remoteAddress, buf);
- } else if (header == 0x7979) {
+ } else {
return decodeExtended(channel, remoteAddress, buf);
}
-
- return null;
}
}
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..6b79ba58b 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 javax.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..4e5f8c96a 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 javax.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 dd7141a2c..2ad4f644b 100644
--- a/src/main/java/org/traccar/protocol/H02ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/H02ProtocolDecoder.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,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;
@@ -176,17 +175,19 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder {
.number("(d+),") // coding scheme
.groupEnd()
.groupBegin()
- .number("-(d+)-(d+.d+),") // latitude
+ .number("-(d+)-(d+.d+),([NS]),") // latitude
.or()
- .number("(d+)(dd.d+),") // latitude
+ .number("(d+)(dd.d+),([NS]),") // latitude
+ .or()
+ .number("(d+)(dd)(d{4}),([NS]),") // latitude
.groupEnd()
- .expression("([NS]),")
.groupBegin()
- .number("-(d+)-(d+.d+),") // longitude
+ .number("-(d+)-(d+.d+),([EW]),") // longitude
.or()
- .number("(d+)(dd.d+),") // longitude
+ .number("(d+)(dd.d+),([EW]),") // longitude
+ .or()
+ .number("(d+)(dd)(d{4}),([EW]),") // longitude
.groupEnd()
- .expression("([EW]),")
.number(" *(d+.?d*),") // speed
.number("(d+.?d*)?,") // course
.number("(?:d+,)?") // battery
@@ -332,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");
}
@@ -349,19 +350,25 @@ public class H02ProtocolDecoder extends BaseProtocolDecoder {
position.setValid(true);
}
- if (parser.hasNext(2)) {
- position.setLatitude(-parser.nextCoordinate());
+ if (parser.hasNext(3)) {
+ position.setLatitude(parser.nextCoordinate());
}
- if (parser.hasNext(2)) {
+ if (parser.hasNext(3)) {
position.setLatitude(parser.nextCoordinate());
}
+ if (parser.hasNext(4)) {
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN_HEM));
+ }
- if (parser.hasNext(2)) {
- position.setLongitude(-parser.nextCoordinate());
+ if (parser.hasNext(3)) {
+ position.setLongitude(parser.nextCoordinate());
}
- if (parser.hasNext(2)) {
+ if (parser.hasNext(3)) {
position.setLongitude(parser.nextCoordinate());
}
+ if (parser.hasNext(4)) {
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN_HEM));
+ }
position.setSpeed(parser.nextDouble(0));
position.setCourse(parser.nextDouble(0));
@@ -384,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 7a765332c..86b8c80d4 100644
--- a/src/main/java/org/traccar/protocol/H02ProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/H02ProtocolEncoder.java
@@ -6,7 +6,7 @@
* 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
+ * 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,
@@ -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..f56c605f0 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 javax.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..aa2d7d852 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 javax.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..02d8e5a8e 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 javax.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 5db7f0bc0..708c74f2a 100644
--- a/src/main/java/org/traccar/protocol/HoopoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/HoopoProtocolDecoder.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,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.model.Position;
@@ -52,7 +52,7 @@ public class HoopoProtocolDecoder extends BaseProtocolDecoder {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
- Date time = new Date(OffsetDateTime.parse(eventData.getString("receiveTime")).toInstant().toEpochMilli());
+ Date time = new Date(OffsetDateTime.parse(json.getString("eventTime")).toInstant().toEpochMilli());
position.setTime(time);
position.setValid(true);
@@ -62,6 +62,10 @@ public class HoopoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_EVENT, eventData.getString("eventType"));
position.set(Position.KEY_BATTERY_LEVEL, eventData.getInt("batteryLevel"));
+ if (json.containsKey("movement")) {
+ position.setSpeed(json.getJsonObject("movement").getInt("Speed"));
+ }
+
return position;
}
diff --git a/src/main/java/org/traccar/protocol/HuaShengProtocol.java b/src/main/java/org/traccar/protocol/HuaShengProtocol.java
index 103f2d501..b1b61e977 100644
--- a/src/main/java/org/traccar/protocol/HuaShengProtocol.java
+++ b/src/main/java/org/traccar/protocol/HuaShengProtocol.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 javax.inject.Inject;
public class HuaShengProtocol extends BaseProtocol {
- public HuaShengProtocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public HuaShengProtocol(Config config) {
+ 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 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..371691d82 100644
--- a/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/HuaShengProtocolDecoder.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/HuabaoProtocol.java b/src/main/java/org/traccar/protocol/HuabaoProtocol.java
index 791672b85..c37918b0e 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 javax.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 871410c44..d0bbeebb5 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 - 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,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;
@@ -34,7 +34,10 @@ import org.traccar.model.Position;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
import java.util.Calendar;
+import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.TimeZone;
@@ -48,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;
@@ -61,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;
@@ -119,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;
}
@@ -142,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);
+ }
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -149,7 +180,19 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
ByteBuf buf = (ByteBuf) msg;
if (buf.getByte(buf.readerIndex()) == '(') {
- return decodeResult(channel, remoteAddress, buf.toString(StandardCharsets.US_ASCII));
+ String sentence = buf.toString(StandardCharsets.US_ASCII);
+ if (sentence.contains("BASE,2")) {
+ DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ String response = sentence.replace("TIME", dateFormat.format(new Date()));
+ if (channel != null) {
+ channel.writeAndFlush(new NetworkMessage(
+ Unpooled.copiedBuffer(response, StandardCharsets.US_ASCII), remoteAddress));
+ }
+ return null;
+ } else {
+ return decodeResult(channel, remoteAddress, sentence);
+ }
}
buf.readUnsignedByte(); // start marker
@@ -163,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) {
@@ -178,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);
@@ -201,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) {
@@ -249,6 +292,10 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
return position;
+ } else if (type == MSG_TRANSPARENT) {
+
+ return decodeTransparent(deviceSession, buf);
+
}
return null;
@@ -266,17 +313,83 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- private Position decodeLocation(DeviceSession deviceSession, ByteBuf buf) {
-
- Position position = new Position(getProtocolName());
- position.setDeviceId(deviceSession.getDeviceId());
+ private void decodeExtension(Position position, ByteBuf buf, int endIndex) {
+ while (buf.readerIndex() < endIndex) {
+ int type = buf.readUnsignedByte();
+ int length = buf.readUnsignedByte();
+ switch (type) {
+ case 0x01:
+ position.set(Position.KEY_ODOMETER, buf.readUnsignedInt() * 100L);
+ break;
+ case 0x02:
+ position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedShort() * 0.1);
+ break;
+ case 0x03:
+ position.set(Position.KEY_OBD_SPEED, buf.readUnsignedShort() * 0.1);
+ break;
+ case 0x80:
+ position.set(Position.KEY_OBD_SPEED, buf.readUnsignedByte());
+ break;
+ case 0x81:
+ position.set(Position.KEY_RPM, buf.readUnsignedShort());
+ break;
+ case 0x82:
+ position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1);
+ break;
+ case 0x83:
+ position.set(Position.KEY_ENGINE_LOAD, buf.readUnsignedByte());
+ break;
+ case 0x84:
+ position.set(Position.KEY_COOLANT_TEMP, buf.readUnsignedByte() - 40);
+ break;
+ case 0x85:
+ position.set(Position.KEY_FUEL_CONSUMPTION, buf.readUnsignedShort());
+ break;
+ case 0x86:
+ position.set("intakeTemp", buf.readUnsignedByte() - 40);
+ break;
+ case 0x87:
+ position.set("intakeFlow", buf.readUnsignedShort());
+ break;
+ case 0x88:
+ position.set("intakePressure", buf.readUnsignedByte());
+ break;
+ case 0x89:
+ position.set(Position.KEY_THROTTLE, buf.readUnsignedByte());
+ break;
+ case 0x8B:
+ position.set(Position.KEY_VIN, buf.readCharSequence(17, StandardCharsets.US_ASCII).toString());
+ break;
+ case 0x8C:
+ position.set(Position.KEY_OBD_ODOMETER, buf.readUnsignedInt() * 100L);
+ break;
+ case 0x8D:
+ position.set(Position.KEY_ODOMETER_TRIP, buf.readUnsignedShort() * 1000L);
+ break;
+ case 0x8E:
+ position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedByte());
+ break;
+ case 0xA0:
+ String codes = buf.readCharSequence(length, StandardCharsets.US_ASCII).toString();
+ position.set(Position.KEY_DTCS, codes.replace(',', ' '));
+ break;
+ case 0xCC:
+ position.set(Position.KEY_ICCID, buf.readCharSequence(20, StandardCharsets.US_ASCII).toString());
+ break;
+ default:
+ buf.skipBytes(length);
+ break;
+ }
+ }
+ }
- 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));
@@ -294,19 +407,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) {
@@ -333,6 +455,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;
@@ -346,6 +471,11 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_BATTERY, Integer.parseInt(lockStatus.substring(2, 5)) * 0.01);
}
break;
+ case 0x80:
+ buf.readUnsignedByte(); // content
+ endIndex = buf.writerIndex() - 2;
+ decodeExtension(position, buf, endIndex);
+ break;
case 0x91:
position.set(Position.KEY_BATTERY, buf.readUnsignedShort() * 0.1);
position.set(Position.KEY_RPM, buf.readUnsignedShort());
@@ -383,11 +513,21 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1);
break;
case 0xD4:
- case 0xFE:
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
@@ -396,6 +536,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();
@@ -423,6 +571,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;
@@ -440,6 +598,105 @@ 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 {
+ 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;
}
@@ -468,7 +725,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();
@@ -496,24 +754,141 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
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);
- if (locationType == 0) {
+ 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;
+ 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;
+ }
+ }
+ decodeCoordinates(position, buf);
+ position.setTime(time);
+ break;
+ case 0x03:
+ count = buf.readUnsignedByte();
+ for (int i = 0; i < count; i++) {
+ int id = buf.readUnsignedShort();
+ int length = buf.readUnsignedByte();
+ switch (id) {
+ 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;
+ default:
+ break;
+ }
+ buf.skipBytes(length);
+ }
+ 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..ed4289d73 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 javax.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..aa1f4ff5b 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 javax.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..b1a91cca9 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 javax.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..0d288f4bf 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 javax.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..5148e8ab0 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 javax.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..763457641 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 javax.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
new file mode 100644
index 000000000..78aa6c81c
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/JidoProtocol.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 javax.inject.Inject;
+
+public class JidoProtocol extends BaseProtocol {
+
+ @Inject
+ public JidoProtocol(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 JidoProtocolDecoder(JidoProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/JidoProtocolDecoder.java b/src/main/java/org/traccar/protocol/JidoProtocolDecoder.java
new file mode 100644
index 000000000..98fb36e11
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/JidoProtocolDecoder.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 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.protocol;
+
+import io.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.session.DeviceSession;
+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 java.net.SocketAddress;
+import java.util.regex.Pattern;
+
+public class JidoProtocolDecoder extends BaseProtocolDecoder {
+
+ public JidoProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ private static final Pattern PATTERN = new PatternBuilder()
+ .text("*")
+ .number("(d+),") // imei
+ .number("(d+),") // command
+ .expression("([AV]),").optional() // validity
+ .number("(dd)(dd)(dd),") // date (ddmmyy)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .number("(d+)(dd.d+),") // latitude
+ .expression("([NS]),")
+ .number("(d+)(dd.d+),") // longitude
+ .expression("([EW]),")
+ .groupBegin()
+ .number("(d+),") // speed
+ .number("(d+),") // odometer
+ .number("(d+),") // course
+ .number("(-?d+),") // altitude
+ .number("(d+),") // satellites
+ .number("d+,") // gsm 1
+ .number("d+,") // gsm 2
+ .number("([01]),") // charging
+ .number("(d+),") // battery level
+ .expression("([YKN]),") // mode
+ .number("([01]),") // lock
+ .number("[^,]+,") // accelerometer x
+ .number("[^,]+,") // accelerometer y
+ .number("[^,]+,") // accelerometer z
+ .or()
+ .expression("[^,]*,") // data
+ .groupEnd()
+ .number("xx") // checksum
+ .compile();
+
+ private String decodeAlarm(int type) {
+ switch (type) {
+ case 3:
+ return Position.ALARM_LOW_BATTERY;
+ case 4:
+ return Position.ALARM_TAMPERING;
+ 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;
+ }
+
+ 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(parser.nextInt()));
+
+ if (parser.hasNext()) {
+ position.setValid(parser.next().equals("A"));
+ } else {
+ position.setValid(true);
+ }
+
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+ position.setLatitude(parser.nextCoordinate());
+ position.setLongitude(parser.nextCoordinate());
+
+ if (parser.hasNext(9)) {
+
+ position.setSpeed(UnitsConverter.knotsFromKph(parser.nextInt()));
+
+ position.set(Position.KEY_ODOMETER, parser.nextInt());
+
+ position.setCourse(parser.nextInt());
+ position.setAltitude(parser.nextInt());
+
+ position.set(Position.KEY_SATELLITES, parser.nextInt());
+ position.set(Position.KEY_CHARGE, parser.nextInt() > 0);
+ position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt());
+ position.set("mode", parser.next());
+ position.set(Position.KEY_BLOCKED, parser.nextInt() > 0);
+
+ }
+
+ return position;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/JpKorjarProtocol.java b/src/main/java/org/traccar/protocol/JpKorjarProtocol.java
index fe5b2480d..30c8e9977 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 javax.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/Jt600Protocol.java b/src/main/java/org/traccar/protocol/Jt600Protocol.java
index 37c82f741..bf0b3379e 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 javax.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 37c1674d4..9ed44f565 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;
@@ -141,7 +141,9 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
int version = BitUtil.from(buf.readUnsignedByte(), 4);
buf.readUnsignedShort(); // length
- while (buf.readableBytes() > 1) {
+ boolean responseRequired = false;
+
+ while (buf.readableBytes() >= 17) {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
@@ -160,6 +162,9 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_ALARM, BitUtil.check(status, 2) ? Position.ALARM_GEOFENCE_EXIT : null);
position.set(Position.KEY_ALARM, BitUtil.check(status, 3) ? Position.ALARM_POWER_CUT : null);
position.set(Position.KEY_ALARM, BitUtil.check(status, 4) ? Position.ALARM_VIBRATION : null);
+ if (BitUtil.check(status, 5)) {
+ responseRequired = true;
+ }
position.set(Position.KEY_BLOCKED, BitUtil.check(status, 7));
position.set(Position.KEY_ALARM, BitUtil.check(status, 8 + 3) ? Position.ALARM_LOW_BATTERY : null);
position.set(Position.KEY_ALARM, BitUtil.check(status, 8 + 6) ? Position.ALARM_FAULT : null);
@@ -172,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));
@@ -196,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 {
@@ -232,7 +238,15 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
}
- buf.readUnsignedByte(); // index
+ int index = buf.readUnsignedByte();
+
+ if (channel != null && responseRequired) {
+ if (protocolVersion < 0x19) {
+ channel.writeAndFlush(new NetworkMessage("(P35)", remoteAddress));
+ } else {
+ channel.writeAndFlush(new NetworkMessage("(P69,0," + index + ")", remoteAddress));
+ }
+ }
return positions;
}
@@ -343,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));
@@ -361,6 +375,64 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private static final Pattern PATTERN_P45 = new PatternBuilder()
+ .text("(")
+ .number("(d+),") // id
+ .text("P45,") // type
+ .number("(dd)(dd)(dd),") // date (ddmmyy)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .number("(d+.d+),([NS]),") // latitude
+ .number("(d+.d+),([EW]),") // longitude
+ .expression("([AV]),") // validity
+ .number("(d+),") // speed
+ .number("(d+),") // course
+ .number("d+,") // event source
+ .number("d+,") // unlock verification
+ .number("(d+),") // rfid
+ .number("d+,") // password verification
+ .number("d+,") // incorrect password count
+ .number("(d+),") // index
+ .any()
+ .compile();
+
+ private Position decodeP45(String sentence, Channel channel, SocketAddress remoteAddress) {
+
+ Parser parser = new Parser(PATTERN_P45, 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.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setValid(parser.next().equals("A"));
+
+ position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble()));
+ position.setCourse(parser.nextDouble());
+
+ String rfid = parser.next();
+ if (!rfid.equals("0000000000")) {
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, rfid);
+ }
+
+ int index = parser.nextInt();
+
+ if (channel != null) {
+ channel.writeAndFlush(new NetworkMessage("(P69,0," + index + ")", remoteAddress));
+ }
+
+ return position;
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -374,6 +446,8 @@ public class Jt600ProtocolDecoder extends BaseProtocolDecoder {
String sentence = buf.toString(StandardCharsets.US_ASCII);
if (sentence.contains("W01")) {
return decodeW01(sentence, channel, remoteAddress);
+ } else if (sentence.contains("P45")) {
+ return decodeP45(sentence, channel, remoteAddress);
} else {
return decodeU01(sentence, channel, remoteAddress);
}
diff --git a/src/main/java/org/traccar/protocol/KenjiProtocol.java b/src/main/java/org/traccar/protocol/KenjiProtocol.java
index 90c0c511c..8d78c8c56 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 javax.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..521274de5 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 javax.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..d7c236c4f 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;
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..0edea6095 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 javax.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..bbebd51ed 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 javax.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..809fafc90 100644
--- a/src/main/java/org/traccar/protocol/LacakProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/LacakProtocolDecoder.java
@@ -19,7 +19,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/LaipacProtocol.java b/src/main/java/org/traccar/protocol/LaipacProtocol.java
index 1d561dbd2..249d3bcbe 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 javax.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..e9570ee11 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;
@@ -253,8 +253,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..7e13e23d0 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 javax.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..a23ea0f57 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 javax.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..6809d800c 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 javax.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..38a67f9a4 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 javax.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..492e86605 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 javax.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..cf65a2db3 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 javax.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..10215eb7c 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 javax.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..492094ce3 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 javax.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..f3b56973a 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);
@@ -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..c6eba8fe1 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 javax.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 5eab10498..343141dca 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 - 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,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());
@@ -418,12 +414,21 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
case 0x07:
position.set(Position.KEY_RSSI, buf.readUnsignedByte());
break;
+ case 0x14:
+ position.set(Position.KEY_OUTPUT, buf.readUnsignedByte());
+ break;
+ case 0x15:
+ position.set(Position.KEY_INPUT, buf.readUnsignedByte());
+ 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;
@@ -432,7 +437,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()));
@@ -446,6 +452,9 @@ public class MeitrackProtocolDecoder extends BaseProtocolDecoder {
case 0x0B:
position.setAltitude(buf.readShortLE());
break;
+ case 0x16:
+ position.set(Position.PREFIX_ADC + 1, buf.readUnsignedShortLE() * 0.01);
+ break;
case 0x19:
position.set(Position.KEY_BATTERY, buf.readUnsignedShortLE() * 0.01);
break;
@@ -482,7 +491,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);
@@ -514,8 +524,30 @@ 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;
+ default:
+ buf.skipBytes(length);
+ break;
+ }
}
positions.add(position);
@@ -524,13 +556,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));
}
}
@@ -546,6 +578,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();
@@ -570,7 +609,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;
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..ccbc4db4c 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 javax.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 652ba3f6a..84ba75e7c 100644
--- a/src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MictrackProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2019 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2020 Roeland Boeters (roeland@geodelta.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -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;
@@ -114,14 +114,18 @@ public class MictrackProtocolDecoder extends BaseProtocolDecoder {
}
}
- private void decodeWifi(Network network, String data) {
+ private void decodeWifi(Network network, String data, boolean hasSsid) {
String[] values = data.split(",");
- for (int i = 0; i < values.length / 2; i++) {
- network.addWifiAccessPoint(WifiAccessPoint.from(values[i * 2], Integer.parseInt(values[i * 2 + 1])));
+ int step = hasSsid ? 3 : 2;
+ int offset = hasSsid ? 1 : 0;
+ for (int i = 0; i < values.length / step; i++) {
+ network.addWifiAccessPoint(WifiAccessPoint.from(
+ values[i * step + offset], Integer.parseInt(values[i * step + offset + 1])));
}
}
- private void decodeNetwork(Position position, String data, boolean hasWifi, boolean hasCell) throws ParseException {
+ private void decodeNetwork(
+ Position position, String data, boolean hasWifi, boolean hasSsid, boolean hasCell) throws ParseException {
int index = 0;
String[] values = data.split("\\+");
@@ -130,7 +134,7 @@ public class MictrackProtocolDecoder extends BaseProtocolDecoder {
Network network = new Network();
if (hasWifi) {
- decodeWifi(network, values[index++]);
+ decodeWifi(network, values[index++], hasSsid);
}
if (hasCell) {
@@ -231,19 +235,22 @@ public class MictrackProtocolDecoder extends BaseProtocolDecoder {
decodeLocation(position, fragments[4]);
break;
case "R1":
- decodeNetwork(position, fragments[4], true, false);
+ decodeNetwork(position, fragments[4], true, false, false);
break;
case "R2":
case "R3":
- decodeNetwork(position, fragments[4], false, true);
+ decodeNetwork(position, fragments[4], false, false, true);
break;
case "R12":
case "R13":
- decodeNetwork(position, fragments[4], true, true);
+ decodeNetwork(position, fragments[4], true, false, true);
break;
case "RH":
decodeStatus(position, fragments[4]);
break;
+ case "Y1":
+ decodeNetwork(position, fragments[4], true, true, false);
+ break;
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/MilesmateProtocol.java b/src/main/java/org/traccar/protocol/MilesmateProtocol.java
index 822711603..59212e791 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 javax.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 82534ecd8..44599accc 100644
--- a/src/main/java/org/traccar/protocol/MiniFinderProtocol.java
+++ b/src/main/java/org/traccar/protocol/MiniFinderProtocol.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,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 javax.inject.Inject;
+
public class MiniFinderProtocol extends BaseProtocol {
- public MiniFinderProtocol() {
+ @Inject
+ public MiniFinderProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_SET_TIMEZONE,
Command.TYPE_VOICE_MONITORING,
@@ -38,10 +42,10 @@ 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) {
- pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ';'));
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new CharacterDelimiterFrameDecoder(1024, ";\0", ";"));
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new MiniFinderProtocolEncoder(MiniFinderProtocol.this));
diff --git a/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java b/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java
index 2b7a960c4..f2e5eb905 100644
--- a/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/MiniFinderProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2014 - 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.
@@ -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("![3A-D],.*")) {
+ if (deviceSession == null || !sentence.matches("![35A-D],.*")) {
return null;
}
@@ -161,6 +161,19 @@ public class MiniFinderProtocolDecoder extends BaseProtocolDecoder {
return position;
+ } else if (type.equals("5")) {
+
+ String[] values = sentence.split(",");
+
+ getLastLocation(position, null);
+
+ position.set(Position.KEY_RSSI, Integer.parseInt(values[1]));
+ if (values.length >= 4) {
+ position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(values[3]));
+ }
+
+ return position;
+
} else if (type.equals("B") || type.equals("D")) {
Parser parser = new Parser(PATTERN_BD, sentence);
diff --git a/src/main/java/org/traccar/protocol/Minifinder2Protocol.java b/src/main/java/org/traccar/protocol/Minifinder2Protocol.java
index f8801db74..5499a274e 100644
--- a/src/main/java/org/traccar/protocol/Minifinder2Protocol.java
+++ b/src/main/java/org/traccar/protocol/Minifinder2Protocol.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 javax.inject.Inject;
+
public class Minifinder2Protocol extends BaseProtocol {
- public Minifinder2Protocol() {
- addServer(new TrackerServer(false, getName()) {
+ @Inject
+ public Minifinder2Protocol(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, 1200, 2, 2, 4, 0, true));
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..0b08badb8 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 - 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,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;
@@ -50,7 +50,7 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
public static final int MSG_SERVICES = 0x03;
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;
}
@@ -181,7 +181,11 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
position.setDeviceId(deviceSession.getDeviceId());
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 +198,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;
@@ -260,8 +266,16 @@ 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 0x40:
buf.readUnsignedIntLE(); // timestamp
diff --git a/src/main/java/org/traccar/protocol/MobilogixProtocol.java b/src/main/java/org/traccar/protocol/MobilogixProtocol.java
index 28380a2af..1b06c2249 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 javax.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 f3b70e40c..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;
@@ -47,9 +47,9 @@ public class MobilogixProtocolDecoder extends BaseProtocolDecoder {
.number("(d+.d+)") // battery
.groupBegin()
.text(",")
- .number("(d)") // valid
+ .number("(d)") // satellites
.number("(d)") // rssi
- .number("(d),") // satellites
+ .number("(d),") // valid
.number("(-?d+.d+),") // latitude
.number("(-?d+.d+),") // longitude
.number("(d+.?d*),") // speed
@@ -127,12 +127,12 @@ public class MobilogixProtocolDecoder extends BaseProtocolDecoder {
if (parser.hasNext(7)) {
+ position.set(Position.KEY_SATELLITES, parser.nextInt());
+ position.set(Position.KEY_RSSI, 6 * parser.nextInt() - 111);
+
position.setValid(parser.nextInt() > 0);
position.setFixTime(position.getDeviceTime());
- position.set(Position.KEY_RSSI, parser.nextInt());
- position.set(Position.KEY_SATELLITES, parser.nextInt());
-
position.setLatitude(parser.nextDouble());
position.setLongitude(parser.nextDouble());
position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble()));
diff --git a/src/main/java/org/traccar/protocol/MoovboxProtocol.java b/src/main/java/org/traccar/protocol/MoovboxProtocol.java
index 7b554266f..16438e122 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 javax.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..3101c9b75 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 javax.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..019fe4fa9 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 javax.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..e085b6221 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 javax.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..1190bf527 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 javax.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..46a6c33a5 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 javax.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..640a77803 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 javax.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..388f141f8 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 javax.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/NavtelecomFrameDecoder.java b/src/main/java/org/traccar/protocol/NavtelecomFrameDecoder.java
index 0fb82528b..2ab7d11a9 100644
--- a/src/main/java/org/traccar/protocol/NavtelecomFrameDecoder.java
+++ b/src/main/java/org/traccar/protocol/NavtelecomFrameDecoder.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.
@@ -30,7 +30,12 @@ public class NavtelecomFrameDecoder extends BaseFrameDecoder {
protected Object decode(
ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception {
- if (buf.getByte(buf.readerIndex()) == '@') {
+ if (buf.getByte(buf.readerIndex()) == 0x7f) {
+
+ buf.skipBytes(1);
+ return null;
+
+ } else if (buf.getByte(buf.readerIndex()) == '@') {
int length = buf.getUnsignedShortLE(12) + 12 + 2 + 2;
if (buf.readableBytes() >= length) {
diff --git a/src/main/java/org/traccar/protocol/NavtelecomProtocol.java b/src/main/java/org/traccar/protocol/NavtelecomProtocol.java
index 29ce8c41e..50013d1a4 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 javax.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 bdcc12c4c..08b1a8d0f 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;
@@ -195,6 +195,9 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder {
for (int j = 0; j < bits.length(); j++) {
if (bits.get(j)) {
+
+ int value;
+
switch (j + 1) {
case 1:
position.set(Position.KEY_INDEX, buf.readUnsignedIntLE());
@@ -205,8 +208,12 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder {
case 3:
position.setDeviceTime(new Date(buf.readUnsignedIntLE() * 1000));
break;
+ case 8:
+ value = buf.readUnsignedByte();
+ position.setValid(BitUtil.check(value, 1));
+ position.set(Position.KEY_SATELLITES, BitUtil.from(value, 2));
+ break;
case 9:
- position.setValid(true);
position.setFixTime(new Date(buf.readUnsignedIntLE() * 1000));
break;
case 10:
@@ -221,6 +228,83 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder {
case 13:
position.setSpeed(UnitsConverter.knotsFromKph(buf.readFloatLE()));
break;
+ case 14:
+ position.setCourse(buf.readUnsignedShortLE());
+ break;
+ case 15:
+ position.set(Position.KEY_ODOMETER, buf.readFloatLE());
+ break;
+ case 19:
+ position.set(Position.KEY_POWER, buf.readShortLE() * 0.001);
+ break;
+ case 20:
+ position.set(Position.KEY_BATTERY, buf.readShortLE() * 0.001);
+ break;
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ position.set(Position.PREFIX_ADC + (j + 2 - 21), buf.readUnsignedShortLE() * 0.001);
+ break;
+ case 29:
+ value = buf.readUnsignedByte();
+ for (int k = 0; k <= 7; k++) {
+ position.set(Position.PREFIX_IN + (k + 1), BitUtil.check(value, k));
+ }
+ break;
+ case 31:
+ value = buf.readUnsignedByte();
+ for (int k = 0; k <= 3; k++) {
+ position.set(Position.PREFIX_OUT + (k + 1), BitUtil.check(value, k));
+ }
+ break;
+ case 33:
+ case 34:
+ position.set(Position.PREFIX_COUNT + (j + 2 - 33), buf.readUnsignedIntLE());
+ break;
+ case 35:
+ case 36:
+ position.set("freq" + (j + 2 - 35), buf.readUnsignedShortLE());
+ break;
+ case 37:
+ position.set(Position.KEY_HOURS, buf.readUnsignedIntLE());
+ break;
+ case 38:
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ value = buf.readUnsignedShortLE();
+ position.set("fuel" + (j + 2 - 38), (value < 65500) ? value : null);
+ break;
+ case 44:
+ value = buf.readUnsignedShortLE();
+ position.set(Position.KEY_FUEL_LEVEL, (value < 65500) ? value : null);
+ break;
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ value = buf.readByte();
+ 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;
default:
buf.skipBytes(getItemLength(j + 1));
break;
@@ -235,12 +319,11 @@ public class NavtelecomProtocolDecoder extends BaseProtocolDecoder {
positions.add(position);
}
- int checksum = buf.readUnsignedByte();
if (channel != null) {
ByteBuf response = Unpooled.buffer();
response.writeCharSequence(type, StandardCharsets.US_ASCII);
response.writeByte(count);
- response.writeByte(checksum);
+ response.writeByte(Checksum.crc8(Checksum.CRC8_EGTS, response.nioBuffer()));
channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
}
diff --git a/src/main/java/org/traccar/protocol/NdtpV6FrameDecoder.java b/src/main/java/org/traccar/protocol/NdtpV6FrameDecoder.java
new file mode 100644
index 000000000..5b610013a
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/NdtpV6FrameDecoder.java
@@ -0,0 +1,32 @@
+/*
+ * 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 io.netty.channel.ChannelHandlerContext;
+import org.traccar.BaseFrameDecoder;
+
+public class NdtpV6FrameDecoder extends BaseFrameDecoder {
+
+ @Override
+ protected Object decode(
+ ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception {
+
+ return buf;
+ }
+
+}
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..ce0dbbef2
--- /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 javax.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..0787b6562 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 javax.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..f27e4afb8 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 javax.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..0fbe0c689 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 javax.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..626991029 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 javax.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..7ed488e38 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 javax.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..e7ef10945 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 javax.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..94f450426 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 javax.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..0539bada6 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 javax.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..29c8bc1b9 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 javax.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..dd400c779 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 javax.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..5443b4ffc 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 javax.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
new file mode 100644
index 000000000..fb09f0abb
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/OrbcommProtocol.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.protocol;
+
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestEncoder;
+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 javax.inject.Inject;
+
+public class OrbcommProtocol extends BaseProtocol {
+
+ @Inject
+ public OrbcommProtocol(Config config) {
+ addClient(new TrackerClient(config, getName()) {
+ @Override
+ 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, config));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java b/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java
new file mode 100644
index 000000000..1164d72a1
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java
@@ -0,0 +1,124 @@
+/*
+ * 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 io.netty.handler.codec.http.FullHttpResponse;
+import org.traccar.BasePipelineFactory;
+import org.traccar.BaseProtocolDecoder;
+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 java.io.StringReader;
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.TimeZone;
+
+public class OrbcommProtocolDecoder extends BaseProtocolDecoder {
+
+ public OrbcommProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ FullHttpResponse response = (FullHttpResponse) msg;
+ String content = response.content().toString(StandardCharsets.UTF_8);
+ JsonObject json = Json.createReader(new StringReader(content)).readObject();
+
+ if (channel != null && !json.getString("NextStartUTC").isEmpty()) {
+ OrbcommProtocolPoller poller =
+ BasePipelineFactory.getHandler(channel.pipeline(), OrbcommProtocolPoller.class);
+ if (poller != null) {
+ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ poller.setStartTime(dateFormat.parse(json.getString("NextStartUTC")));
+ }
+ }
+
+ if (json.get("Messages").getValueType() == JsonValue.ValueType.NULL) {
+ return null;
+ }
+
+ LinkedList<Position> positions = new LinkedList<>();
+
+ JsonArray messages = json.getJsonArray("Messages");
+ for (int i = 0; i < messages.size(); i++) {
+ JsonObject message = messages.getJsonObject(i);
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, message.getString("MobileID"));
+ if (deviceSession != null) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ position.setDeviceTime(dateFormat.parse(message.getString("MessageUTC")));
+
+ JsonArray fields = message.getJsonObject("Payload").getJsonArray("Fields");
+ for (int j = 0; j < fields.size(); j++) {
+ JsonObject field = fields.getJsonObject(j);
+ String value = field.getString("Value");
+ switch (field.getString("Name").toLowerCase()) {
+ case "eventtime":
+ position.setDeviceTime(new Date(Long.parseLong(value) * 1000));
+ break;
+ case "latitude":
+ position.setLatitude(Integer.parseInt(value) / 60000.0);
+ break;
+ case "longitude":
+ position.setLongitude(Integer.parseInt(value) / 60000.0);
+ break;
+ case "speed":
+ position.setSpeed(UnitsConverter.knotsFromKph(Integer.parseInt(value)));
+ break;
+ case "heading":
+ int heading = Integer.parseInt(value);
+ position.setCourse(heading <= 360 ? heading : 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (position.getLatitude() != 0 && position.getLongitude() != 0) {
+ position.setValid(true);
+ position.setFixTime(position.getDeviceTime());
+ } else {
+ getLastLocation(position, position.getDeviceTime());
+ }
+
+ positions.add(position);
+
+ }
+ }
+
+ return positions.isEmpty() ? null : positions;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/OrbcommProtocolPoller.java b/src/main/java/org/traccar/protocol/OrbcommProtocolPoller.java
new file mode 100644
index 000000000..0f57bfb49
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/OrbcommProtocolPoller.java
@@ -0,0 +1,74 @@
+/*
+ * 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.DefaultFullHttpRequest;
+import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpMethod;
+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.Protocol;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import java.net.SocketAddress;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+public class OrbcommProtocolPoller extends BaseProtocolPoller {
+
+ private final String accessId;
+ private final String password;
+ private final String host;
+
+ private Date startTime = new Date();
+
+ public void setStartTime(Date startTime) {
+ this.startTime = startTime;
+ }
+
+ 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
+ protected void sendRequest(Channel channel, SocketAddress remoteAddress) {
+
+ QueryStringEncoder encoder = new QueryStringEncoder("/GLGW/2/RestMessages.svc/JSON/get_return_messages/");
+ encoder.addParam("access_id", accessId);
+ encoder.addParam("password", password);
+
+ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ encoder.addParam("start_utc", dateFormat.format(startTime));
+
+ HttpRequest request = new DefaultFullHttpRequest(
+ HttpVersion.HTTP_1_1, HttpMethod.GET, encoder.toString(), Unpooled.buffer());
+ request.headers().add(HttpHeaderNames.HOST, host);
+ request.headers().add(HttpHeaderNames.CONTENT_LENGTH, 0);
+ channel.writeAndFlush(request);
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/OrionProtocol.java b/src/main/java/org/traccar/protocol/OrionProtocol.java
index 8485ae638..2dec7cd06 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 javax.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..a86bc70d7 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 javax.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..0099be456 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 javax.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..62b873be7 100644
--- a/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/OutsafeProtocolDecoder.java
@@ -19,7 +19,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;
diff --git a/src/main/java/org/traccar/protocol/OwnTracksProtocol.java b/src/main/java/org/traccar/protocol/OwnTracksProtocol.java
index 0086371d8..9ad337f19 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 javax.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..71ac87168 100644
--- a/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/OwnTracksProtocolDecoder.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.UnitsConverter;
import org.traccar.model.Position;
diff --git a/src/main/java/org/traccar/protocol/PacificTrackProtocol.java b/src/main/java/org/traccar/protocol/PacificTrackProtocol.java
index 08991ab64..709729ef1 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 javax.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..1d13eea95 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 javax.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..aa45a0def 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 javax.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..b2101b18d 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 javax.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..69666cc0e 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 javax.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..028de5424 100644
--- a/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/PolteProtocolDecoder.java
@@ -19,7 +19,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;
diff --git a/src/main/java/org/traccar/protocol/PortmanProtocol.java b/src/main/java/org/traccar/protocol/PortmanProtocol.java
index b7faae08a..de78013fa 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 javax.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..b77dd97bf 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 javax.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..f5e904541 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 javax.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..49eb6847f 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 javax.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..73f978cbd 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 javax.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..b272582a4 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 javax.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..d72774f47 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 javax.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..d5d30e8e8 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 javax.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..58345f025 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 javax.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..a406f6306 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 javax.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..63ca3476c 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 javax.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..9d88c6d72 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 javax.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..db70396ee 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 javax.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..0d50db01e 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 javax.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..1d4b419bb 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 javax.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..d3b41e93e
--- /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 javax.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..28a3ac29c
--- /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 javax.json.Json;
+import javax.json.JsonArray;
+import javax.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..9b9c00cb2 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 javax.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..ab2bc5842 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 javax.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..109d91b16 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 javax.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..99a9686f6 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 javax.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 5c2885a8b..77df0deb7 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,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;
@@ -50,6 +49,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;
@@ -102,6 +102,12 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
case 5:
position.set(Position.KEY_IGNITION, readValue(buf, length, false) == 1);
break;
+ case 29:
+ position.set(Position.KEY_POWER, readValue(buf, length, false));
+ break;
+ case 30:
+ position.set(Position.KEY_BATTERY, readValue(buf, length, false) * 0.001);
+ break;
case 74:
position.set(Position.PREFIX_TEMP + 3, readValue(buf, length, true) * 0.1);
break;
@@ -110,22 +116,19 @@ public class RuptelaProtocolDecoder extends BaseProtocolDecoder {
case 80:
position.set(Position.PREFIX_TEMP + (id - 78), readValue(buf, length, true) * 0.1);
break;
- case 198:
- if (readValue(buf, length, false) > 0) {
- position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED);
- }
- break;
- case 199:
- case 200:
+ case 134:
if (readValue(buf, length, false) > 0) {
position.set(Position.KEY_ALARM, Position.ALARM_BRAKING);
}
break;
- case 201:
+ case 136:
if (readValue(buf, length, false) > 0) {
position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION);
}
break;
+ case 197:
+ position.set(Position.KEY_RPM, readValue(buf, length, false) * 0.125);
+ break;
default:
position.set(Position.PREFIX_IO + id, readValue(buf, length, false));
break;
@@ -294,7 +297,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;
@@ -303,6 +306,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..f904ed9ff 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 javax.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 71aff1a65..cf665c6ba 100644
--- a/src/main/java/org/traccar/protocol/S168ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/S168ProtocolDecoder.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.
@@ -17,10 +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.UnitsConverter;
+import org.traccar.model.CellTower;
+import org.traccar.model.Network;
import org.traccar.model.Position;
+import org.traccar.model.WifiAccessPoint;
import java.net.SocketAddress;
import java.text.DateFormat;
@@ -48,9 +51,14 @@ public class S168ProtocolDecoder extends BaseProtocolDecoder {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
+ Network network = new Network();
+
String content = values[4];
String[] fragments = content.split(";");
for (String fragment : fragments) {
+ if (fragment.isEmpty()) {
+ continue;
+ }
int dataIndex = fragment.indexOf(':');
String type = fragment.substring(0, dataIndex);
@@ -70,12 +78,44 @@ public class S168ProtocolDecoder extends BaseProtocolDecoder {
position.setCourse(Integer.parseInt(values[index++]));
position.setAltitude(Integer.parseInt(values[index++]));
break;
+ case "CELL":
+ int cellCount = Integer.parseInt(values[index++]);
+ int mcc = Integer.parseInt(values[index++], 16);
+ int mnc = Integer.parseInt(values[index++], 16);
+ for (int i = 0; i < cellCount; i++) {
+ network.addCellTower(CellTower.from(
+ mcc, mnc, Integer.parseInt(values[index++], 16), Integer.parseInt(values[index++], 16),
+ Integer.parseInt(values[index++], 16)));
+ }
+ break;
+ case "WIFI":
+ int wifiCount = Integer.parseInt(values[index++]);
+ for (int i = 0; i < wifiCount; i++) {
+ network.addWifiAccessPoint(WifiAccessPoint.from(
+ values[index++].replace('-', ':'), Integer.parseInt(values[index++])));
+ }
+ break;
+ case "STATUS":
+ position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(values[index++]));
+ position.set(Position.KEY_RSSI, Integer.parseInt(values[index++]));
+ break;
default:
break;
}
}
- return position.getAttributes().containsKey(Position.KEY_SATELLITES) ? position : null;
+ if (network.getCellTowers() != null || network.getWifiAccessPoints() != null) {
+ position.setNetwork(network);
+ }
+ if (!position.hasAttribute(Position.KEY_SATELLITES)) {
+ getLastLocation(position, null);
+ }
+
+ if (position.getNetwork() != null || !position.getAttributes().isEmpty()) {
+ return position;
+ } else {
+ return null;
+ }
}
}
diff --git a/src/main/java/org/traccar/protocol/SabertekProtocol.java b/src/main/java/org/traccar/protocol/SabertekProtocol.java
index 0ec847b60..403243cdc 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 javax.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..1a0e7b0e9 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 javax.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..ea44bf868 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 javax.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..d90033e38 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 javax.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..9a268af62 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 javax.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..4ed2bb51d 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;
@@ -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..f12958a50 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 javax.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..7ae26f634 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 javax.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..cb7efb7ee 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 javax.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..22b343537 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 javax.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..0676aa629 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 javax.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..6bd802fed 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 javax.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..d578fa705 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 javax.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..aa23bfac5 100644
--- a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,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(
+ @Override
+ protected void init() {
+ setFormat(getConfig().getString(
getProtocolName() + ".format", "#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(getProtocolName() + ".dateFormat", "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..33c3a4776 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 javax.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..d010df858 100644
--- a/src/main/java/org/traccar/protocol/StartekProtocol.java
+++ b/src/main/java/org/traccar/protocol/StartekProtocol.java
@@ -21,19 +21,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 javax.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) {
+ 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/StartekProtocolDecoder.java b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java
index 042518cb2..8e3624cb5 100644
--- a/src/main/java/org/traccar/protocol/StartekProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/StartekProtocolDecoder.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,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;
@@ -70,17 +70,30 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder {
.number("(x+),") // outputs
.number("(x+)|") // power
.number("(x+)") // battery
- .groupBegin()
- .text("|")
- .expression("([^,]+)").optional() // adc
+ .expression("([^,]+)?") // adc
.groupBegin()
.text(",")
.number("d,") // extended
- .expression("([^,]+)?,") // fuel
- .expression("([^,]+)?,?") // temperature
+ .expression("([^,]+)?") // fuel
+ .groupBegin()
+ .text(",")
+ .expression("([^,]+)?") // temperature
+ .groupBegin()
+ .text(",")
+ .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("?")
+ .groupEnd("?")
.groupEnd("?")
.groupEnd("?")
- .any()
.compile();
private String decodeAlarm(int value) {
@@ -181,7 +194,7 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder {
if (parser.hasNext()) {
String[] adc = parser.next().split("\\|");
- for (int i = 0; i < adc.length; i++) {
+ for (int i = 1; i < adc.length; i++) {
position.set(Position.PREFIX_ADC + (i + 1), Integer.parseInt(adc[i], 16) * 0.01);
}
}
@@ -208,6 +221,24 @@ public class StartekProtocolDecoder extends BaseProtocolDecoder {
}
}
+ if (parser.hasNext(6)) {
+ 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());
+ 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());
+ }
+
return position;
}
diff --git a/src/main/java/org/traccar/protocol/StbProtocol.java b/src/main/java/org/traccar/protocol/StbProtocol.java
index 002ed86c7..af4e0d2c4 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 javax.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..641359bfd 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,15 +15,12 @@
*/
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;
@@ -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..83b5db3bb 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 javax.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..4253b761b 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 javax.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 2d00ea81e..047a1822a 100644
--- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.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,10 +17,13 @@ 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.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;
@@ -34,10 +37,17 @@ import java.nio.charset.StandardCharsets;
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.LinkedList;
+import java.util.List;
import java.util.TimeZone;
+import java.util.stream.Collectors;
public class SuntechProtocolDecoder extends BaseProtocolDecoder {
+ private boolean universal;
private String prefix;
private int protocolType;
@@ -46,10 +56,16 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
private boolean includeRpm;
private boolean includeTemp;
+ private ByteBuf crash;
+
public SuntechProtocolDecoder(Protocol protocol) {
super(protocol);
}
+ public boolean getUniversal() {
+ return universal;
+ }
+
public String getPrefix() {
return prefix;
}
@@ -59,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) {
@@ -68,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) {
@@ -77,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) {
@@ -86,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) {
@@ -95,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(
@@ -185,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;
}
@@ -358,7 +381,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();
@@ -381,6 +404,8 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
break;
}
}
+ } else {
+ position.set("serial", attribute.trim());
}
remaining -= attribute.length() + 1;
}
@@ -448,7 +473,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;
}
@@ -461,6 +486,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;
@@ -550,7 +583,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)) {
@@ -559,7 +594,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++]);
@@ -654,19 +690,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)) {
@@ -732,6 +760,89 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private Collection<Position> decodeCrashReport(Channel channel, SocketAddress remoteAddress, ByteBuf buf) {
+
+ if (buf.getByte(buf.readerIndex() + 3) != ';') {
+ return null;
+ }
+
+ String[] values = buf.readCharSequence(23, StandardCharsets.US_ASCII).toString().split(";");
+
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, values[1]);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ int currentIndex = Integer.parseInt(values[2]);
+ int totalIndex = Integer.parseInt(values[3]);
+
+ if (crash == null) {
+ crash = Unpooled.buffer();
+ }
+
+ crash.writeBytes(buf.readSlice(buf.readableBytes() - 3));
+
+ if (currentIndex == totalIndex) {
+
+ LinkedList<Position> positions = new LinkedList<>();
+
+ Date crashTime = new DateBuilder()
+ .setDate(crash.readUnsignedByte(), crash.readUnsignedByte(), crash.readUnsignedByte())
+ .setTime(crash.readUnsignedByte(), crash.readUnsignedByte(), crash.readUnsignedByte())
+ .getDate();
+
+ List<Date> times = Arrays.asList(
+ new Date(crashTime.getTime() - 3000),
+ new Date(crashTime.getTime() - 2000),
+ new Date(crashTime.getTime() - 1000),
+ new Date(crashTime.getTime() + 1000));
+
+ for (Date time : times) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ position.setValid(true);
+ position.setTime(time);
+ position.setLatitude(crash.readIntLE() * 0.0000001);
+ position.setLongitude(crash.readIntLE() * 0.0000001);
+ position.setSpeed(UnitsConverter.knotsFromKph(crash.readUnsignedShort() * 0.01));
+ position.setCourse(crash.readUnsignedShort() * 0.01);
+
+ StringBuilder value = new StringBuilder("[");
+ for (int i = 0; i < 100; i++) {
+ if (value.length() > 1) {
+ value.append(",");
+ }
+ value.append("[");
+ value.append(crash.readShortLE());
+ value.append(",");
+ value.append(crash.readShortLE());
+ value.append(",");
+ value.append(crash.readShortLE());
+ value.append("]");
+ }
+ value.append("]");
+
+ position.set(Position.KEY_G_SENSOR, value.toString());
+
+ positions.add(position);
+
+ }
+
+ crash.release();
+ crash = null;
+
+ return positions;
+
+ } else {
+
+ return null;
+
+ }
+
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -740,14 +851,18 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder {
if (buf.getByte(buf.readerIndex() + 1) == 0) {
+ universal = true;
return decodeBinary(channel, remoteAddress, buf);
} else {
- String[] values = buf.toString(StandardCharsets.US_ASCII).split(";");
+ String[] values = buf.toString(StandardCharsets.US_ASCII).split(";", -1);
prefix = values[0];
- if (prefix.length() < 5) {
+ if (prefix.equals("CRR")) {
+ return decodeCrashReport(channel, remoteAddress, buf);
+ } else if (prefix.length() < 5) {
+ universal = true;
return decodeUniversal(channel, remoteAddress, values);
} else if (prefix.endsWith("HTE")) {
return decodeTravelReport(channel, remoteAddress, values);
diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java
index 3b4995110..a4faacf13 100644
--- a/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/SuntechProtocolEncoder.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.
@@ -27,49 +27,95 @@ public class SuntechProtocolEncoder extends StringProtocolEncoder {
super(protocol);
}
- private String getPrefix(Channel channel) {
- String prefix = "SA200CMD";
+ @Override
+ protected Object encodeCommand(Channel channel, Command command) {
+
+ boolean universal = false;
+ String prefix = "SA200";
if (channel != null) {
SuntechProtocolDecoder protocolDecoder =
BasePipelineFactory.getHandler(channel.pipeline(), SuntechProtocolDecoder.class);
if (protocolDecoder != null) {
+ universal = protocolDecoder.getUniversal();
String decoderPrefix = protocolDecoder.getPrefix();
if (decoderPrefix != null && decoderPrefix.length() > 5) {
- prefix = decoderPrefix.substring(0, decoderPrefix.length() - 3) + "CMD";
+ prefix = decoderPrefix.substring(0, decoderPrefix.length() - 3);
}
}
}
- return prefix;
- }
-
- @Override
- protected Object encodeCommand(Channel channel, Command command) {
- String prefix = getPrefix(channel);
+ if (universal) {
+ return encodeUniversalCommand(command);
+ } else {
+ return encodeLegacyCommand(prefix, command);
+ }
+ }
+ protected Object encodeUniversalCommand(Command command) {
switch (command.getType()) {
case Command.TYPE_REBOOT_DEVICE:
- return formatCommand(command, prefix + ";%s;02;Reboot\r", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "CMD;%s;03;03\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_POSITION_SINGLE:
- return formatCommand(command, prefix + ";%s;02;\r", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, "CMD;%s;03;01\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_OUTPUT_CONTROL:
- if (command.getAttributes().containsKey(Command.KEY_DATA)) {
- if (command.getAttributes().get(Command.KEY_DATA).equals("1")) {
- return formatCommand(command, prefix + ";%s;02;Enable%s\r",
- Command.KEY_UNIQUE_ID, Command.KEY_INDEX);
- } else {
- return formatCommand(command, prefix + ";%s;02;Disable%s\r",
- Command.KEY_UNIQUE_ID, Command.KEY_INDEX);
+ if (command.getAttributes().get(Command.KEY_DATA).equals("1")) {
+ switch (command.getInteger(Command.KEY_INDEX)) {
+ case 1:
+ return formatCommand(command, "CMD;%s;04;01\r", Command.KEY_UNIQUE_ID);
+ case 2:
+ return formatCommand(command, "CMD;%s;04;03\r", Command.KEY_UNIQUE_ID);
+ case 3:
+ return formatCommand(command, "CMD;%s;04;09\r", Command.KEY_UNIQUE_ID);
+ default:
+ return null;
}
+ } else {
+ switch (command.getInteger(Command.KEY_INDEX)) {
+ case 1:
+ return formatCommand(command, "CMD;%s;04;02\r", Command.KEY_UNIQUE_ID);
+ case 2:
+ return formatCommand(command, "CMD;%s;04;04\r", Command.KEY_UNIQUE_ID);
+ case 3:
+ return formatCommand(command, "CMD;%s;04;10\r", Command.KEY_UNIQUE_ID);
+ default:
+ return null;
+ }
+ }
+ 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;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:
+ return formatCommand(command, "CMD;%s;04;04\r", Command.KEY_UNIQUE_ID);
+ default:
+ return null;
+ }
+ }
+
+ 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;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",
+ Command.KEY_UNIQUE_ID, Command.KEY_INDEX);
+ } else {
+ return formatCommand(command, prefix + "CMD;%s;02;Disable%s\r",
+ Command.KEY_UNIQUE_ID, Command.KEY_INDEX);
}
case Command.TYPE_ENGINE_STOP:
- return formatCommand(command, prefix + ";%s;02;Enable1\r", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, prefix + "CMD;%s;02;Enable1\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_ENGINE_RESUME:
- return formatCommand(command, prefix + ";%s;02;Disable1\r", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, prefix + "CMD;%s;02;Disable1\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_ALARM_ARM:
- return formatCommand(command, prefix + ";%s;02;Enable2\r", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, prefix + "CMD;%s;02;Enable2\r", Command.KEY_UNIQUE_ID);
case Command.TYPE_ALARM_DISARM:
- return formatCommand(command, prefix + ";%s;02;Disable2\r", Command.KEY_UNIQUE_ID);
+ return formatCommand(command, prefix + "CMD;%s;02;Disable2\r", Command.KEY_UNIQUE_ID);
default:
return null;
}
diff --git a/src/main/java/org/traccar/protocol/SupermateProtocol.java b/src/main/java/org/traccar/protocol/SupermateProtocol.java
index 46625ddc7..4290b7126 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 javax.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..7c6624f7c 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 javax.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..68cf40d84 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 javax.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..cedac275f 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 javax.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..3be161fb8 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 - 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.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,41 @@ 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 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 +328,44 @@ public class T55ProtocolDecoder extends BaseProtocolDecoder {
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 +381,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 +419,8 @@ 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);
}
return null;
diff --git a/src/main/java/org/traccar/protocol/T57Protocol.java b/src/main/java/org/traccar/protocol/T57Protocol.java
index f67f82318..4bafe8c6d 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 javax.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/T800xProtocol.java b/src/main/java/org/traccar/protocol/T800xProtocol.java
index 8b91265cb..253c3cb73 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 javax.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 7f7873e50..6e09e6e3b 100644
--- a/src/main/java/org/traccar/protocol/T800xProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/T800xProtocolDecoder.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;
@@ -58,6 +58,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;
@@ -77,7 +78,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder {
}
}
- private String decodeAlarm(int value) {
+ private String decodeAlarm1(int value) {
switch (value) {
case 1:
return Position.ALARM_POWER_CUT;
@@ -107,6 +108,28 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder {
}
}
+ private String decodeAlarm2(int value) {
+ switch (value) {
+ case 1:
+ case 4:
+ return Position.ALARM_REMOVING;
+ case 2:
+ return Position.ALARM_TAMPERING;
+ case 3:
+ return Position.ALARM_SOS;
+ case 5:
+ return Position.ALARM_FALL_DOWN;
+ case 6:
+ return Position.ALARM_LOW_BATTERY;
+ case 14:
+ return Position.ALARM_GEOFENCE_ENTER;
+ case 15:
+ return Position.ALARM_GEOFENCE_EXIT;
+ default:
+ return null;
+ }
+ }
+
private Date readDate(ByteBuf buf) {
return new DateBuilder()
.setYear(BcdUtil.readInteger(buf, 2))
@@ -145,7 +168,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());
@@ -232,6 +255,11 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder {
return null;
}
+ private double decodeBleTemp(ByteBuf buf) {
+ int value = buf.readUnsignedShort();
+ return (BitUtil.check(value, 15) ? -BitUtil.to(value, 15) : BitUtil.to(value, 15)) * 0.01;
+ }
+
private Position decodeBle(
Channel channel, DeviceSession deviceSession, ByteBuf buf, int type, int index, ByteBuf imei) {
@@ -281,7 +309,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder {
position.set("tag" + i + "Id", ByteBufUtil.hexDump(buf.readSlice(6)));
position.set("tag" + i + "Battery", buf.readUnsignedByte() * 0.01 + 2);
buf.readUnsignedByte(); // battery level
- position.set("tag" + i + "Temp", buf.readUnsignedShort() * 0.01);
+ position.set("tag" + i + "Temp", decodeBleTemp(buf));
position.set("tag" + i + "Humidity", buf.readUnsignedShort() * 0.01);
position.set("tag" + i + "LightSensor", buf.readUnsignedShort());
position.set("tag" + i + "Rssi", buf.readUnsignedByte() - 128);
@@ -290,7 +318,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder {
position.set("tag" + i + "Id", ByteBufUtil.hexDump(buf.readSlice(6)));
position.set("tag" + i + "Battery", buf.readUnsignedByte() * 0.01 + 2);
buf.readUnsignedByte(); // battery level
- position.set("tag" + i + "Temp", buf.readUnsignedShort() * 0.01);
+ position.set("tag" + i + "Temp", decodeBleTemp(buf));
position.set("tag" + i + "Door", buf.readUnsignedByte() > 0);
position.set("tag" + i + "Rssi", buf.readUnsignedByte() - 128);
break;
@@ -369,7 +397,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder {
}
int alarm = buf.readUnsignedByte();
- position.set(Position.KEY_ALARM, decodeAlarm(alarm));
+ position.set(Position.KEY_ALARM, header != 0x2727 ? decodeAlarm1(alarm) : decodeAlarm2(alarm));
if (header != 0x2727) {
@@ -384,7 +412,7 @@ public class T800xProtocolDecoder extends BaseProtocolDecoder {
if (BitUtil.check(status, 6)) {
- position.setValid(!BitUtil.check(status, 7));
+ position.setValid(true);
position.setTime(readDate(buf));
position.setAltitude(buf.readFloatLE());
position.setLongitude(buf.readFloatLE());
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..943ec98c5 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 javax.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..e5e84b7c4 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;
diff --git a/src/main/java/org/traccar/protocol/TechTltProtocol.java b/src/main/java/org/traccar/protocol/TechTltProtocol.java
index 0cffb452d..191dd9ccc 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 javax.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/TechtoCruzFrameDecoder.java b/src/main/java/org/traccar/protocol/TechtoCruzFrameDecoder.java
new file mode 100644
index 000000000..8b9152e8b
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/TechtoCruzFrameDecoder.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 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.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import org.traccar.BaseFrameDecoder;
+
+import java.nio.charset.StandardCharsets;
+
+public class TechtoCruzFrameDecoder extends BaseFrameDecoder {
+
+ @Override
+ protected Object decode(
+ ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception {
+
+ int lengthStart = buf.readerIndex() + 3;
+ int lengthEnd = buf.indexOf(lengthStart, buf.writerIndex(), (byte) ',');
+ if (lengthEnd > 0) {
+ int length = lengthStart
+ + Integer.parseInt(buf.toString(lengthStart, lengthEnd - lengthStart, StandardCharsets.US_ASCII));
+ if (buf.readableBytes() >= length) {
+ return buf.readRetainedSlice(length);
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java b/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java
index 890a8abb1..265a3eb64 100644
--- a/src/main/java/org/traccar/protocol/TechtoCruzProtocol.java
+++ b/src/main/java/org/traccar/protocol/TechtoCruzProtocol.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 javax.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) {
- pipeline.addLast(new LineBasedFrameDecoder(1024));
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new TechtoCruzFrameDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new TechtoCruzProtocolDecoder(TechtoCruzProtocol.this));
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..54e860d79 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 javax.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..9e9cbb50e 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 javax.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..9ef7864ca 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 javax.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..38283cb64 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 javax.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 89ae48b3a..929eca8aa 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 - 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.model.Device;
+import org.traccar.session.DeviceSession;
import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.config.Keys;
@@ -39,11 +39,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 +59,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) {
@@ -116,7 +124,8 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
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 +154,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();
}
@@ -181,191 +189,193 @@ 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(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(90, null, (p, b) -> p.set(Position.KEY_DOOR, b.readUnsignedShort()));
+ register(115, fmbXXX, (p, b) -> p.set(Position.KEY_COOLANT_TEMP, b.readShort() * 0.1));
+ 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("cid", b.readUnsignedShort()));
+ register(206, fmbXXX, (p, b) -> p.set("lac", b.readUnsignedShort()));
+ 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(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;
+ }
+ });
}
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 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) {
- 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 != 0) {
- cellTower.setOperator(operator);
+ 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 cid = (Integer) position.getAttributes().remove("cid");
+ Integer lac = (Integer) position.getAttributes().remove("lac");
+ if (cid != null && lac != null) {
+ CellTower cellTower = CellTower.fromLacCid(getConfig(), lac, cid);
+ long operator = position.getInteger(Position.KEY_OPERATOR);
+ if (operator >= 1000) {
+ cellTower.setOperator(operator);
+ }
+ position.setNetwork(new Network(cellTower));
}
- position.setNetwork(new Network(cellTower));
}
}
@@ -384,7 +394,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 +432,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 +491,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 +499,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 +507,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 +515,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 +569,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
}
}
- decodeNetwork(position);
+ decodeNetwork(position, model);
}
@@ -574,10 +585,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());
@@ -597,9 +608,9 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder {
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 +647,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 +661,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
new file mode 100644
index 000000000..73219cc5e
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/TeraTrackProtocol.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 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 javax.inject.Inject;
+
+public class TeraTrackProtocol extends BaseProtocol {
+
+ @Inject
+ public TeraTrackProtocol(Config config) {
+ addServer(new TrackerServer(config, getName(), false) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) {
+ pipeline.addLast(new JsonFrameDecoder());
+ pipeline.addLast(new StringEncoder());
+ pipeline.addLast(new StringDecoder());
+ pipeline.addLast(new TeraTrackProtocolDecoder(TeraTrackProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java
new file mode 100644
index 000000000..313210f63
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/TeraTrackProtocolDecoder.java
@@ -0,0 +1,79 @@
+/*
+ * 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.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 java.io.StringReader;
+import java.net.SocketAddress;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.TimeZone;
+
+public class TeraTrackProtocolDecoder extends BaseProtocolDecoder {
+
+ public TeraTrackProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ JsonObject json = Json.createReader(new StringReader((String) msg)).readObject();
+
+ String deviceId = json.getString("MDeviceID");
+ String imei = json.getString("IMEI");
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, deviceId, imei);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ position.setTime(dateFormat.parse(json.getString("DateTime")));
+
+ position.setValid(true);
+ position.setLatitude(Double.parseDouble(json.getString("Latitude")));
+ position.setLongitude(Double.parseDouble(json.getString("Longitude")));
+ 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_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")));
+ position.set(Position.KEY_RSSI, Integer.parseInt(json.getString("GSM")));
+
+ if (channel != null && json.getString("MessageAck").equals("1")) {
+ channel.writeAndFlush(new NetworkMessage("{01}", remoteAddress));
+ }
+
+ return position;
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/ThinkPowerProtocol.java b/src/main/java/org/traccar/protocol/ThinkPowerProtocol.java
index ece1b0544..38bf078aa 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 javax.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..782b0a352 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 javax.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..f709a1183
--- /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 javax.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..150e83ab3 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 javax.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..cf09886f5 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 javax.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..b343c3b33 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 - 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,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;
@@ -36,11 +35,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 +99,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 +307,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()) {
@@ -419,7 +465,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);
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..b10271f7d 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 javax.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..9d83388c9 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 javax.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..e078c425b 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 javax.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..339d2fc8d 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 javax.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..b15373d71 100644
--- a/src/main/java/org/traccar/protocol/TopinProtocol.java
+++ b/src/main/java/org/traccar/protocol/TopinProtocol.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 javax.inject.Inject;
+
public class TopinProtocol extends BaseProtocol {
- public TopinProtocol() {
+ @Inject
+ public TopinProtocol(Config config) {
setSupportedDataCommands(
Command.TYPE_SOS_NUMBER);
- 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 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 267bce562..a1d5481db 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;
@@ -93,6 +93,19 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder {
return negative ? -result : result;
}
+ private String decodeAlarm(int alarms) {
+ if (BitUtil.check(alarms, 0)) {
+ return Position.ALARM_VIBRATION;
+ }
+ if (BitUtil.check(alarms, 1)) {
+ return Position.ALARM_OVERSPEED;
+ }
+ if (BitUtil.check(alarms, 4)) {
+ return Position.ALARM_LOW_POWER;
+ }
+ return null;
+ }
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -158,17 +171,7 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder {
if (buf.readableBytes() >= 5) {
position.setAltitude(buf.readShort());
-
- int alarms = buf.readUnsignedByte();
- if (BitUtil.check(alarms, 0)) {
- position.set(Position.KEY_ALARM, Position.ALARM_VIBRATION);
- }
- if (BitUtil.check(alarms, 1)) {
- position.set(Position.KEY_ALARM, Position.ALARM_OVERSPEED);
- }
- if (BitUtil.check(alarms, 4)) {
- position.set(Position.KEY_ALARM, Position.ALARM_LOW_POWER);
- }
+ position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
}
ByteBuf content = Unpooled.buffer();
@@ -190,10 +193,12 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder {
getLastLocation(position, null);
+ ByteBuf content = buf.retainedSlice(buf.readerIndex(), buf.readableBytes() - 2);
+
position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
position.set(Position.KEY_VERSION_FW, buf.readUnsignedByte());
buf.readUnsignedByte(); // timezone
- int interval = buf.readUnsignedByte();
+ buf.readUnsignedByte(); // interval
if (buf.readableBytes() >= 1 + 2) {
position.set(Position.KEY_RSSI, buf.readUnsignedByte());
}
@@ -207,8 +212,6 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_HEART_RATE, buf.readUnsignedByte());
}
- ByteBuf content = Unpooled.buffer();
- content.writeByte(interval);
sendResponse(channel, length, type, content);
return position;
@@ -246,6 +249,10 @@ public class TopinProtocolDecoder extends BaseProtocolDecoder {
mcc, mnc, buf.readUnsignedShort(), buf.readUnsignedShort(), buf.readUnsignedByte()));
}
+ if (buf.readableBytes() > 2) {
+ position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
+ }
+
position.setNetwork(network);
ByteBuf content = Unpooled.buffer();
diff --git a/src/main/java/org/traccar/protocol/TotemProtocol.java b/src/main/java/org/traccar/protocol/TotemProtocol.java
index f8cda8358..9ab36fd0b 100644
--- a/src/main/java/org/traccar/protocol/TotemProtocol.java
+++ b/src/main/java/org/traccar/protocol/TotemProtocol.java
@@ -20,18 +20,39 @@ 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 javax.inject.Inject;
+
public class TotemProtocol extends BaseProtocol {
- public TotemProtocol() {
+ @Inject
+ public TotemProtocol(Config config) {
setSupportedDataCommands(
+ Command.TYPE_CUSTOM,
+ Command.TYPE_REBOOT_DEVICE,
+ Command.TYPE_FACTORY_RESET,
+ Command.TYPE_GET_VERSION,
+ Command.TYPE_POSITION_SINGLE,
+ Command.TYPE_ENGINE_RESUME,
+ Command.TYPE_ENGINE_STOP
+ );
+
+ setTextCommandEncoder(new TotemProtocolSmsEncoder(this));
+ setSupportedTextCommands(
+ Command.TYPE_CUSTOM,
+ Command.TYPE_REBOOT_DEVICE,
+ Command.TYPE_FACTORY_RESET,
+ Command.TYPE_GET_VERSION,
+ Command.TYPE_POSITION_SINGLE,
Command.TYPE_ENGINE_RESUME,
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..9d0d794f8 100644
--- a/src/main/java/org/traccar/protocol/TotemProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TotemProtocolDecoder.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;
@@ -140,8 +140,12 @@ public class TotemProtocolDecoder extends BaseProtocolDecoder {
.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,6 +170,7 @@ 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()
@@ -320,7 +325,7 @@ 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());
@@ -346,7 +351,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());
@@ -379,8 +384,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 +413,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());
diff --git a/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java b/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java
index a96dd1ee3..4b22ade03 100644
--- a/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/TotemProtocolEncoder.java
@@ -6,7 +6,7 @@
* 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
+ * 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,
@@ -19,6 +19,7 @@ package org.traccar.protocol;
import org.traccar.StringProtocolEncoder;
import org.traccar.model.Command;
import org.traccar.Protocol;
+import org.traccar.helper.Checksum;
public class TotemProtocolEncoder extends StringProtocolEncoder {
@@ -26,20 +27,41 @@ public class TotemProtocolEncoder extends StringProtocolEncoder {
super(protocol);
}
- @Override
- protected Object encodeCommand(Command command) {
-
- initDevicePassword(command, "000000");
-
+ public static String formatContent(Command command) {
switch (command.getType()) {
+ case Command.TYPE_CUSTOM:
+ return String.format("%s,%s",
+ command.getAttributes().get(Command.KEY_DEVICE_PASSWORD),
+ command.getAttributes().get(Command.KEY_DATA)
+ );
+ case Command.TYPE_REBOOT_DEVICE:
+ return String.format("%s,006", command.getAttributes().get(Command.KEY_DEVICE_PASSWORD));
+ case Command.TYPE_FACTORY_RESET:
+ return String.format("%s,007", command.getAttributes().get(Command.KEY_DEVICE_PASSWORD));
+ case Command.TYPE_GET_VERSION:
+ return String.format("%s,056", command.getAttributes().get(Command.KEY_DEVICE_PASSWORD));
+ case Command.TYPE_POSITION_SINGLE:
+ return String.format("%s,012", command.getAttributes().get(Command.KEY_DEVICE_PASSWORD));
// Assuming PIN 8 (Output C) is the power wire, like manual says but it can be PIN 5,7,8
case Command.TYPE_ENGINE_STOP:
- return formatCommand(command, "*%s,025,C,1#", Command.KEY_DEVICE_PASSWORD);
+ return String.format("%s,025,C,1", command.getAttributes().get(Command.KEY_DEVICE_PASSWORD));
case Command.TYPE_ENGINE_RESUME:
- return formatCommand(command, "*%s,025,C,0#", Command.KEY_DEVICE_PASSWORD);
+ return String.format("%s,025,C,0", command.getAttributes().get(Command.KEY_DEVICE_PASSWORD));
default:
return null;
}
}
+ @Override
+ protected Object encodeCommand(Command command) {
+
+ initDevicePassword(command, "000000");
+
+ String commandString = formatContent(command);
+ String builtCommand = String.format("$$%04dCF%s", 10 + commandString.getBytes().length, commandString);
+
+ return String.format("%s%02X", builtCommand, Checksum.xor(builtCommand));
+
+ }
+
}
diff --git a/src/main/java/org/traccar/protocol/TotemProtocolSmsEncoder.java b/src/main/java/org/traccar/protocol/TotemProtocolSmsEncoder.java
new file mode 100644
index 000000000..8656f8a5c
--- /dev/null
+++ b/src/main/java/org/traccar/protocol/TotemProtocolSmsEncoder.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 Irving Gonzalez
+ * 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.protocol;
+
+import org.traccar.StringProtocolEncoder;
+import org.traccar.model.Command;
+import org.traccar.Protocol;
+
+public class TotemProtocolSmsEncoder extends StringProtocolEncoder {
+
+ public TotemProtocolSmsEncoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ protected Object encodeCommand(Command command) {
+
+ initDevicePassword(command, "000000");
+
+ return String.format("*%s#", TotemProtocolEncoder.formatContent(command));
+ }
+
+}
diff --git a/src/main/java/org/traccar/protocol/Tr20Protocol.java b/src/main/java/org/traccar/protocol/Tr20Protocol.java
index 1b71db03f..615fdab28 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 javax.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..162cbe651 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 javax.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..4236144a3 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 javax.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..b7637e6f3 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 javax.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/TramigoProtocol.java b/src/main/java/org/traccar/protocol/TramigoProtocol.java
index f683ccc5d..79a59abd3 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 javax.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..21dd78da3 100644
--- a/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TramigoProtocolDecoder.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.DateUtil;
diff --git a/src/main/java/org/traccar/protocol/TrvProtocol.java b/src/main/java/org/traccar/protocol/TrvProtocol.java
index 99a164cf1..e67afbda2 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 javax.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 05312b820..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;
@@ -59,7 +59,7 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder {
.number("(d)") // acc
.number("(dd)") // arm status
.number("(dd)") // working mode
- .number("(?:[0-2]{3})?,")
+ .number("(?:d{3,5})?,")
.number("(d+),") // mcc
.number("(d+),") // mnc
.number("(d+),") // lac
@@ -183,7 +183,7 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder {
return position;
- } else if (type.equals("AP01") || type.equals("AP10") || type.equals("YP03")) {
+ } else if (type.equals("AP01") || type.equals("AP10") || type.equals("YP03") || type.equals("YP14")) {
Parser parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
diff --git a/src/main/java/org/traccar/protocol/Tt8850Protocol.java b/src/main/java/org/traccar/protocol/Tt8850Protocol.java
index 66a13da9e..ab109e274 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 javax.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..cc3bc9b52 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 javax.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..d25757b63 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 javax.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 249915b39..8e84a6781 100644
--- a/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/TzoneProtocolDecoder.java
@@ -17,10 +17,13 @@ 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.config.Keys;
import org.traccar.helper.BcdUtil;
import org.traccar.helper.BitUtil;
import org.traccar.helper.DateBuilder;
@@ -30,6 +33,11 @@ import org.traccar.model.Network;
import org.traccar.model.Position;
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;
public class TzoneProtocolDecoder extends BaseProtocolDecoder {
@@ -37,6 +45,20 @@ public class TzoneProtocolDecoder extends BaseProtocolDecoder {
super(protocol);
}
+ private void sendResponse(Channel channel, SocketAddress remoteAddress, int index) {
+ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+
+ String ack = String.format("@ACK,%d#", index);
+ String time = String.format("@UTC time:%s", dateFormat.format(new Date()));
+
+ ByteBuf response = Unpooled.copiedBuffer(ack + time, StandardCharsets.US_ASCII);
+
+ if (channel != null) {
+ channel.writeAndFlush(new NetworkMessage(response, remoteAddress));
+ }
+ }
+
private String decodeAlarm(Short value) {
switch (value) {
case 0x01:
@@ -261,7 +283,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) {
@@ -348,6 +370,10 @@ public class TzoneProtocolDecoder extends BaseProtocolDecoder {
}
+ if (getConfig().getBoolean(Keys.PROTOCOL_ACK.withPrefix(getProtocolName()))) {
+ sendResponse(channel, remoteAddress, buf.getUnsignedShort(buf.writerIndex() - 6));
+ }
+
return position;
}
diff --git a/src/main/java/org/traccar/protocol/UlbotechProtocol.java b/src/main/java/org/traccar/protocol/UlbotechProtocol.java
index dfe5235f0..57fc47644 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 javax.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..e27088594 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 javax.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..3de4a4732 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 javax.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..53bca849c 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 javax.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..5296402b4 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 javax.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/VnetProtocol.java b/src/main/java/org/traccar/protocol/VnetProtocol.java
index 0fed30e13..dd739f0d9 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 javax.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..efb5fe2fd 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 javax.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..a8fc801e7 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;
diff --git a/src/main/java/org/traccar/protocol/VtfmsProtocol.java b/src/main/java/org/traccar/protocol/VtfmsProtocol.java
index 2826a86e6..482ab4a37 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 javax.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/WatchProtocol.java b/src/main/java/org/traccar/protocol/WatchProtocol.java
index 6dc3bf9fb..600f81328 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 javax.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 4990cfd65..142d1b64f 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 - 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,14 +18,12 @@ 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.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 +39,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);
@@ -89,6 +87,8 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
return Position.ALARM_GEOFENCE_EXIT;
} else if (BitUtil.check(status, 2)) {
return Position.ALARM_GEOFENCE_ENTER;
+ } else if (BitUtil.check(status, 14)) {
+ return Position.ALARM_POWER_CUT;
} else if (BitUtil.check(status, 16)) {
return Position.ALARM_SOS;
} else if (BitUtil.check(status, 17)) {
@@ -142,14 +142,21 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
Network network = new Network();
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;
-
- for (int i = 0; i < cellCount; i++) {
- network.addCellTower(CellTower.from(mcc, mnc,
- Integer.parseInt(values[index++]), Integer.parseInt(values[index++]),
- 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++]);
+ 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));
+ }
+ }
}
if (index < values.length && !values[index].isEmpty()) {
@@ -157,8 +164,11 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
for (int i = 0; i < wifiCount; i++) {
index += 1; // wifi name
- network.addWifiAccessPoint(WifiAccessPoint.from(
- values[index++], Integer.parseInt(values[index++])));
+ String macAddress = values[index++];
+ String rssi = values[index++];
+ if (!macAddress.isEmpty() && !macAddress.equals("0") && !rssi.isEmpty()) {
+ network.addWifiAccessPoint(WifiAccessPoint.from(macAddress, Integer.parseInt(rssi)));
+ }
}
}
@@ -253,6 +263,9 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder {
Position position = decodePosition(deviceSession, buf.toString(StandardCharsets.US_ASCII));
if (type.startsWith("AL")) {
+ if (position != null) {
+ position.set(Position.KEY_ALARM, Position.ALARM_GENERAL);
+ }
sendResponse(channel, id, index, "AL");
}
@@ -305,17 +318,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;
}
@@ -324,7 +361,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..a744349cd 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 javax.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 80299ff08..3d57525b7 100644
--- a/src/main/java/org/traccar/protocol/WialonProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/WialonProtocolDecoder.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,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
@@ -47,13 +47,13 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder {
.compile();
private static final Pattern PATTERN = new PatternBuilder()
- .number("(dd)(dd)(dd);") // date (ddmmyy)
- .number("(dd)(dd)(dd);") // time (hhmmss)
+ .number("(?:NA|(dd)(dd)(dd));") // date (ddmmyy)
+ .number("(?:NA|(dd)(dd)(dd));") // time (hhmmss)
.number("(?:NA|(dd)(dd.d+));") // latitude
.expression("(?:NA|([NS]));")
.number("(?:NA|(ddd)(dd.d+));") // longitude
.expression("(?:NA|([EW]));")
- .number("(d+.?d*)?;") // speed
+ .number("(?:NA|(d+.?d*))?;") // speed
.number("(?:NA|(d+.?d*))?;") // course
.number("(?:NA|(-?d+.?d*));") // altitude
.number("(?:NA|(d+))") // satellites
@@ -95,7 +95,11 @@ public class WialonProtocolDecoder extends BaseProtocolDecoder {
Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());
- position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+ if (parser.hasNext(6)) {
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+ } else {
+ position.setTime(new Date());
+ }
if (parser.hasNext(9)) {
position.setLatitude(parser.nextCoordinate());
diff --git a/src/main/java/org/traccar/protocol/WliProtocol.java b/src/main/java/org/traccar/protocol/WliProtocol.java
index c10ebf505..f7084e55b 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 javax.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..5a0401df4 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 javax.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/WondexProtocolEncoder.java b/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java
index 21f1ee321..fb213dc40 100644
--- a/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java
+++ b/src/main/java/org/traccar/protocol/WondexProtocolEncoder.java
@@ -5,7 +5,7 @@
* 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
+ * 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,
diff --git a/src/main/java/org/traccar/protocol/WristbandProtocol.java b/src/main/java/org/traccar/protocol/WristbandProtocol.java
index 1e5ef2c01..c5d8d4050 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 javax.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..52cf731f0 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 javax.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..913dfaf28 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<>();
@@ -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..5c7329603 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 javax.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..0841d86d5 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 javax.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..65c2a1230 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 javax.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..9e9087609 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 javax.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..e200adb9f 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 javax.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..fb44e2360 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 javax.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/CsvExportProvider.java b/src/main/java/org/traccar/reports/CsvExportProvider.java
new file mode 100644
index 000000000..df55c470e
--- /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 javax.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 66d9e708d..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.sql.SQLException;
-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;
-
-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 SQLException {
- 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 SQLException, 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..30f55ba80
--- /dev/null
+++ b/src/main/java/org/traccar/reports/EventsReportProvider.java
@@ -0,0 +1,169 @@
+/*
+ * 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.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 javax.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: reportUtils.getAccessibleDevices(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: reportUtils.getAccessibleDevices(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..ccbd97fc3
--- /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 javax.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..24fcfb8ab
--- /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 javax.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 6adb00aae..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.sql.SQLException;
-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;
-
-public final class Route {
-
- private Route() {
- }
-
- public static Collection<Position> getObjects(long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to) throws SQLException {
- 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 SQLException, 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..3ee651619
--- /dev/null
+++ b/src/main/java/org/traccar/reports/RouteReportProvider.java
@@ -0,0 +1,102 @@
+/*
+ * 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.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 javax.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 RouteReportProvider {
+
+ private final Config config;
+ private final ReportUtils reportUtils;
+ private final Storage storage;
+
+ @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: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ result.addAll(PositionUtil.getPositions(storage, device.getId(), from, to));
+ }
+ 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> devicesRoutes = new ArrayList<>();
+ ArrayList<String> sheetNames = new ArrayList<>();
+ for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ var positions = PositionUtil.getPositions(storage, device.getId(), from, to);
+ DeviceReportSection deviceRoutes = new DeviceReportSection();
+ deviceRoutes.setDeviceName(device.getName());
+ sheetNames.add(WorkbookUtil.createSafeSheetName(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 2036b0641..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.sql.SQLException;
-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;
-
-public final class Stops {
-
- private Stops() {
- }
-
- private static Collection<StopReport> detectStops(long deviceId, Date from, Date to) throws SQLException {
- 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 SQLException {
- 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 SQLException, 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..ec3fd2215
--- /dev/null
+++ b/src/main/java/org/traccar/reports/StopsReportProvider.java
@@ -0,0 +1,110 @@
+/*
+ * 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.PositionUtil;
+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 javax.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;
+ }
+
+ private Collection<StopReportItem> detectStops(Device device, Date from, Date to) throws StorageException {
+ boolean ignoreOdometer = config.getBoolean(Keys.REPORT_IGNORE_ODOMETER);
+ var positions = PositionUtil.getPositions(storage, device.getId(), from, to);
+ return reportUtils.detectTripsAndStops(device, positions, ignoreOdometer, StopReportItem.class);
+ }
+
+ 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: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ result.addAll(detectStops(device, from, to));
+ }
+ 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: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ Collection<StopReportItem> stops = detectStops(device, from, to);
+ 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/SummaryReportProvider.java
index d576ac1e6..9415f3e81 100644
--- a/src/main/java/org/traccar/reports/Summary.java
+++ b/src/main/java/org/traccar/reports/SummaryReportProvider.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");
@@ -16,31 +16,52 @@
*/
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.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 javax.inject.Inject;
+import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.sql.SQLException;
+import java.nio.file.Paths;
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;
+public class SummaryReportProvider {
-public final class Summary {
+ private final Config config;
+ private final ReportUtils reportUtils;
+ private final PermissionsService permissionsService;
+ private final Storage storage;
- private Summary() {
+ @Inject
+ public SummaryReportProvider(
+ Config config, ReportUtils reportUtils, PermissionsService permissionsService, Storage storage) {
+ this.config = config;
+ this.reportUtils = reportUtils;
+ this.permissionsService = permissionsService;
+ this.storage = storage;
}
- private static SummaryReport calculateSummaryResult(long deviceId, Collection<Position> positions) {
- SummaryReport result = new SummaryReport();
- result.setDeviceId(deviceId);
- result.setDeviceName(Context.getIdentityManager().getById(deviceId).getName());
+ private SummaryReportItem calculateSummaryResult(Device device, Collection<Position> positions) {
+ SummaryReportItem result = new SummaryReportItem();
+ result.setDeviceId(device.getId());
+ result.setDeviceName(device.getName());
if (positions != null && !positions.isEmpty()) {
Position firstPosition = null;
Position previousPosition = null;
@@ -53,14 +74,12 @@ public final class Summary {
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));
+ boolean ignoreOdometer = config.getBoolean(Keys.REPORT_IGNORE_ODOMETER);
+ result.setDistance(PositionUtil.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)) {
+ if (firstPosition.hasAttribute(Position.KEY_HOURS) && previousPosition.hasAttribute(Position.KEY_HOURS)) {
durationMilliseconds =
previousPosition.getLong(Position.KEY_HOURS) - firstPosition.getLong(Position.KEY_HOURS);
result.setEngineHours(durationMilliseconds);
@@ -90,62 +109,67 @@ public final class Summary {
return result;
}
- private static int getDay(long userId, Date date) {
- Calendar calendar = Calendar.getInstance(ReportUtils.getTimezone(userId));
+ private int getDay(long userId, Date date) throws StorageException {
+ Calendar calendar = Calendar.getInstance(UserUtil.getTimezone(
+ permissionsService.getServer(), permissionsService.getUser(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 SQLException {
-
- ArrayList<Position> positions = new ArrayList<>(Context.getDataManager().getPositions(deviceId, from, to));
+ private Collection<SummaryReportItem> calculateSummaryResults(
+ long userId, Device device, Date from, Date to, boolean daily) throws StorageException {
- ArrayList<SummaryReport> results = new ArrayList<>();
+ var positions = PositionUtil.getPositions(storage, device.getId(), from, to);
+ var results = new ArrayList<SummaryReportItem>();
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)));
+ results.add(calculateSummaryResult(device, positions.subList(startIndex, i)));
startIndex = i;
startDay = currentDay;
}
}
- results.add(calculateSummaryResult(deviceId, positions.subList(startIndex, positions.size())));
+ results.add(calculateSummaryResult(device, positions.subList(startIndex, positions.size())));
} else {
- results.add(calculateSummaryResult(deviceId, positions));
+ results.add(calculateSummaryResult(device, positions));
}
return results;
}
- public static Collection<SummaryReport> getObjects(long userId, Collection<Long> deviceIds,
- Collection<Long> groupIds, Date from, Date to, boolean daily) throws SQLException {
- 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));
+ public Collection<SummaryReportItem> getObjects(
+ long userId, Collection<Long> deviceIds,
+ Collection<Long> groupIds, Date from, Date to, boolean daily) throws StorageException {
+ reportUtils.checkPeriodLimit(from, to);
+
+ ArrayList<SummaryReportItem> result = new ArrayList<>();
+ for (Device device: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ Collection<SummaryReportItem> deviceResults = calculateSummaryResults(userId, device, from, to, daily);
+ for (SummaryReportItem summaryReport : deviceResults) {
+ if (summaryReport.getStartTime() != null && summaryReport.getEndTime() != null) {
+ result.add(summaryReport);
+ }
+ }
}
return result;
}
- public static void getExcel(OutputStream outputStream,
+ public void getExcel(OutputStream outputStream,
long userId, Collection<Long> deviceIds, Collection<Long> groupIds,
- Date from, Date to, boolean daily) throws SQLException, 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);
+ 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, jxlsContext);
+ .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 7c0cd6921..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.sql.SQLException;
-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;
-
-public final class Trips {
-
- private Trips() {
- }
-
- private static Collection<TripReport> detectTrips(long deviceId, Date from, Date to) throws SQLException {
- 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 SQLException {
- 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 SQLException, 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..265811354
--- /dev/null
+++ b/src/main/java/org/traccar/reports/TripsReportProvider.java
@@ -0,0 +1,110 @@
+/*
+ * 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.PositionUtil;
+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 javax.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;
+ }
+
+ private Collection<TripReportItem> detectTrips(Device device, Date from, Date to) throws StorageException {
+ boolean ignoreOdometer = config.getBoolean(Keys.REPORT_IGNORE_ODOMETER);
+ var positions = PositionUtil.getPositions(storage, device.getId(), from, to);
+ return reportUtils.detectTripsAndStops(device, positions, ignoreOdometer, TripReportItem.class);
+ }
+
+ 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: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ result.addAll(detectTrips(device, from, to));
+ }
+ 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: reportUtils.getAccessibleDevices(userId, deviceIds, groupIds)) {
+ Collection<TripReportItem> trips = detectTrips(device, from, to);
+ 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/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java
new file mode 100644
index 000000000..a7c420095
--- /dev/null
+++ b/src/main/java/org/traccar/reports/common/ReportUtils.java
@@ -0,0 +1,399 @@
+/*
+ * 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.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.Group;
+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.Request;
+
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+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.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+@Singleton
+public class ReportUtils {
+
+ private final Config config;
+ private final Storage storage;
+ private final PermissionsService permissionsService;
+ private final TripsConfig tripsConfig;
+ private final VelocityEngine velocityEngine;
+ private final Geocoder geocoder;
+
+ @Inject
+ public ReportUtils(
+ Config config, Storage storage, PermissionsService permissionsService,
+ TripsConfig tripsConfig, VelocityEngine velocityEngine, @Nullable Geocoder geocoder) {
+ this.config = config;
+ this.storage = storage;
+ this.permissionsService = permissionsService;
+ this.tripsConfig = tripsConfig;
+ 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 Collection<Device> getAccessibleDevices(
+ 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;
+ }
+
+ 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, ArrayList<Position> positions, int startIndex, int endIndex,
+ boolean ignoreOdometer) throws StorageException {
+
+ 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;
+ }
+ }
+
+ 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(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 StopReportItem calculateStop(
+ Device device, ArrayList<Position> positions, int startIndex, int endIndex, boolean ignoreOdometer) {
+
+ Position startStop = positions.get(startIndex);
+ Position endStop = positions.get(endIndex);
+
+ 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, ArrayList<Position> positions, int startIndex, int endIndex,
+ boolean ignoreOdometer, Class<T> reportClass) throws StorageException {
+
+ if (reportClass.equals(TripReportItem.class)) {
+ return (T) calculateTrip(device, positions, startIndex, endIndex, ignoreOdometer);
+ } else {
+ return (T) calculateStop(device, positions, startIndex, endIndex, ignoreOdometer);
+ }
+ }
+
+ private 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;
+ }
+ }
+ return positions.get(index).getBoolean(Position.KEY_MOTION);
+ }
+
+ public <T extends BaseReportItem> Collection<T> detectTripsAndStops(
+ Device device, Collection<Position> positionCollection, boolean ignoreOdometer,
+ Class<T> reportClass) throws StorageException {
+
+ Collection<T> result = new ArrayList<>();
+
+ ArrayList<Position> positions = new ArrayList<>(positionCollection);
+ 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();
+ 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) {
+ startEventIndex = detected ? startEventIndex : i;
+ startNoEventIndex = -1;
+ } else {
+ startNoEventIndex = i;
+ }
+ }
+
+ 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, startEventIndex, startNoEventIndex, ignoreOdometer, reportClass));
+ detected = false;
+ startEventIndex = -1;
+ startNoEventIndex = -1;
+ }
+ }
+ }
+ if (startEventIndex >= 0 && startEventIndex < positions.size() - 1) {
+ int endIndex = startNoEventIndex >= 0 ? startNoEventIndex : positions.size() - 1;
+ result.add(calculateTripOrStop(
+ device, positions, startEventIndex, endIndex, ignoreOdometer, reportClass));
+ }
+ }
+
+ return result;
+ }
+
+}
diff --git a/src/main/java/org/traccar/reports/model/TripsConfig.java b/src/main/java/org/traccar/reports/common/TripsConfig.java
index 0f0c615d3..52db97b74 100644
--- a/src/main/java/org/traccar/reports/model/TripsConfig.java
+++ b/src/main/java/org/traccar/reports/common/TripsConfig.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");
@@ -14,14 +14,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.reports.model;
+package org.traccar.reports.common;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+@Singleton
public class TripsConfig {
- public TripsConfig() {
+ @Inject
+ public TripsConfig(Config config) {
+ this(
+ 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));
}
- public TripsConfig(double minimalTripDistance, long minimalTripDuration, long minimalParkingDuration,
+ public TripsConfig(
+ double minimalTripDistance, long minimalTripDuration, long minimalParkingDuration,
long minimalNoDataDuration, boolean useIgnition, boolean processInvalidPositions, double speedThreshold) {
this.minimalTripDistance = minimalTripDistance;
this.minimalTripDuration = minimalTripDuration;
@@ -32,74 +49,46 @@ public class TripsConfig {
this.speedThreshold = speedThreshold;
}
- private double minimalTripDistance;
+ private final double minimalTripDistance;
public double getMinimalTripDistance() {
return minimalTripDistance;
}
- public void setMinimalTripDistance(double minimalTripDistance) {
- this.minimalTripDistance = minimalTripDistance;
- }
-
- private long minimalTripDuration;
+ private final long minimalTripDuration;
public long getMinimalTripDuration() {
return minimalTripDuration;
}
- public void setMinimalTripDuration(long minimalTripDuration) {
- this.minimalTripDuration = minimalTripDuration;
- }
-
- private long minimalParkingDuration;
+ private final long minimalParkingDuration;
public long getMinimalParkingDuration() {
return minimalParkingDuration;
}
- public void setMinimalParkingDuration(long minimalParkingDuration) {
- this.minimalParkingDuration = minimalParkingDuration;
- }
-
- private long minimalNoDataDuration;
+ private final long minimalNoDataDuration;
public long getMinimalNoDataDuration() {
return minimalNoDataDuration;
}
- public void setMinimalNoDataDuration(long minimalNoDataDuration) {
- this.minimalNoDataDuration = minimalNoDataDuration;
- }
-
- private boolean useIgnition;
+ private final boolean useIgnition;
public boolean getUseIgnition() {
return useIgnition;
}
- public void setUseIgnition(boolean useIgnition) {
- this.useIgnition = useIgnition;
- }
-
- private boolean processInvalidPositions;
+ private final boolean processInvalidPositions;
public boolean getProcessInvalidPositions() {
return processInvalidPositions;
}
- public void setProcessInvalidPositions(boolean processInvalidPositions) {
- this.processInvalidPositions = processInvalidPositions;
- }
-
- private double speedThreshold;
+ private final double speedThreshold;
public double getSpeedThreshold() {
return speedThreshold;
}
- public void setSpeedThreshold(double speedThreshold) {
- this.speedThreshold = speedThreshold;
- }
-
}
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/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/schedule/ScheduleManager.java b/src/main/java/org/traccar/schedule/ScheduleManager.java
index 5d5054100..6412a186a 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 - 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.
@@ -15,29 +15,39 @@
*/
package org.traccar.schedule;
+import com.google.inject.Injector;
+import org.traccar.LifecycleObject;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
-public class ScheduleManager {
+@Singleton
+public class ScheduleManager implements LifecycleObject {
+ private final Injector injector;
private ScheduledExecutorService executor;
- public void start() {
+ @Inject
+ public ScheduleManager(Injector injector) {
+ this.injector = injector;
+ }
+ @Override
+ public void start() {
executor = Executors.newSingleThreadScheduledExecutor();
-
- new TaskDeviceInactivityCheck().schedule(executor);
- new TaskWebSocketKeepalive().schedule(executor);
-
+ List.of(TaskDeviceInactivityCheck.class, TaskWebSocketKeepalive.class, TaskHealthCheck.class)
+ .forEach(task -> injector.getInstance(task).schedule(executor));
}
+ @Override
public void stop() {
-
if (executor != null) {
executor.shutdown();
executor = null;
}
-
}
}
diff --git a/src/main/java/org/traccar/schedule/ScheduleTask.java b/src/main/java/org/traccar/schedule/ScheduleTask.java
new file mode 100644
index 000000000..1b537213b
--- /dev/null
+++ b/src/main/java/org/traccar/schedule/ScheduleTask.java
@@ -0,0 +1,22 @@
+/*
+ * 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.schedule;
+
+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..57c64dc5b 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 - 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,26 @@
*/
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.Position;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Request;
+import javax.inject.Inject;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-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 +42,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,15 +62,20 @@ 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 {
+ for (Device device : storage.getObjects(Device.class, new Request(new Columns.All()))) {
+ 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);
+ }
}
+ } catch (StorageException e) {
+ LOGGER.warn("Get devices error", e);
}
- Context.getNotificationManager().updateEvents(events);
+ notificationManager.updateEvents(events);
}
private boolean checkDevice(Device device, long currentTime, long checkPeriod) {
diff --git a/src/main/java/org/traccar/api/HealthCheckService.java b/src/main/java/org/traccar/schedule/TaskHealthCheck.java
index 0182cc358..a8c9873ce 100644
--- a/src/main/java/org/traccar/api/HealthCheckService.java
+++ b/src/main/java/org/traccar/schedule/TaskHealthCheck.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.
@@ -13,28 +13,37 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.api;
+package org.traccar.schedule;
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 java.util.TimerTask;
+import javax.inject.Inject;
+import javax.ws.rs.client.Client;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
-public class HealthCheckService {
+public class TaskHealthCheck implements ScheduleTask {
- private static final Logger LOGGER = LoggerFactory.getLogger(HealthCheckService.class);
+ 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 HealthCheckService() {
- 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);
@@ -52,36 +61,31 @@ public class HealthCheckService {
}
}
- public boolean isEnabled() {
- return enabled;
- }
-
- public long getPeriod() {
- return period;
- }
-
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";
}
- public TimerTask createTask() {
- return new TimerTask() {
- @Override
- public void run() {
- LOGGER.debug("Health check running");
- int status = Context.getClient().target(getUrl()).request().get().getStatus();
- if (status == 200) {
- int result = systemD.sd_notify(0, "WATCHDOG=1");
- if (result < 0) {
- LOGGER.warn("Health check notify error {}", result);
- }
- } else {
- LOGGER.warn("Health check failed with status {}", status);
- }
+ @Override
+ public void schedule(ScheduledExecutorService executor) {
+ if (enabled) {
+ executor.scheduleAtFixedRate(this, period, period, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ @Override
+ public void run() {
+ LOGGER.debug("Health check running");
+ int status = client.target(getUrl()).request().get().getStatus();
+ if (status == 200) {
+ int result = systemD.sd_notify(0, "WATCHDOG=1");
+ if (result < 0) {
+ LOGGER.warn("Health check notify error {}", result);
}
- };
+ } else {
+ LOGGER.warn("Health check failed with status {}", status);
+ }
}
interface SystemD extends Library {
diff --git a/src/main/java/org/traccar/schedule/TaskWebSocketKeepalive.java b/src/main/java/org/traccar/schedule/TaskWebSocketKeepalive.java
index 953b0efea..e6c2e8b6d 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 javax.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..37a42d827
--- /dev/null
+++ b/src/main/java/org/traccar/session/ConnectionManager.java
@@ -0,0 +1,374 @@
+/*
+ * 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 javax.inject.Inject;
+import javax.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)) {
+ 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..9d2350012
--- /dev/null
+++ b/src/main/java/org/traccar/session/cache/CacheManager.java
@@ -0,0 +1,425 @@
+/*
+ * 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.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.ScheduledModel;
+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 javax.inject.Inject;
+import javax.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 ScheduledModel) {
+ if (((ScheduledModel) before).getCalendarId() != ((ScheduledModel) 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);
+
+ 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 ScheduledModel) {
+ var scheduled = (ScheduledModel) object;
+ if (scheduled.getCalendarId() > 0) {
+ var calendar = storage.getObject(Calendar.class, new Request(
+ new Columns.All(), new Condition.Equals("id", scheduled.getCalendarId())));
+ links.computeIfAbsent(Notification.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(Notification.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..62f6a3de2
--- /dev/null
+++ b/src/main/java/org/traccar/session/state/OverspeedProcessor.java
@@ -0,0 +1,65 @@
+/*
+ * 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, long minimalDuration, long geofenceId) {
+
+ state.setEvent(null);
+
+ boolean oldState = state.getOverspeedState();
+ if (oldState) {
+ boolean newState = position.getSpeed() > speedLimit;
+ if (newState) {
+ 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);
+
+ }
+ }
+ } else {
+ state.setOverspeedState(false);
+ state.setOverspeedTime(null);
+ state.setOverspeedGeofenceId(0);
+ }
+ } else if (position != null && position.getSpeed() > speedLimit) {
+ state.setOverspeedState(true);
+ state.setOverspeedTime(position.getFixTime());
+ state.setOverspeedGeofenceId(geofenceId);
+ }
+ }
+
+}
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..51b161594 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 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,16 +16,14 @@
*/
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.Client;
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 java.io.UnsupportedEncodingException;
@@ -34,8 +32,7 @@ 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,7 +56,7 @@ public class HttpSmsClient implements SmsManager {
authorization = null;
}
}
- template = Context.getConfig().getString(Keys.SMS_HTTP_TEMPLATE).trim();
+ template = config.getString(Keys.SMS_HTTP_TEMPLATE).trim();
if (template.charAt(0) == '{' || template.charAt(0) == '[') {
encode = false;
mediaType = MediaType.APPLICATION_JSON_TYPE;
@@ -83,7 +81,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 +89,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..9ab25d9cb 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,7 @@ import org.traccar.notification.MessageException;
public interface SmsManager {
- void sendMessageSync(
+ void sendMessage(
String destAddress, String message, boolean command) throws InterruptedException, MessageException;
- void sendMessageAsync(
- String destAddress, String message, boolean command);
-
}
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..edf089f37 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.Client;
import javax.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..3e3483818
--- /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 javax.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
new file mode 100644
index 000000000..a049a641c
--- /dev/null
+++ b/src/main/java/org/traccar/storage/DatabaseStorage.java
@@ -0,0 +1,410 @@
+/*
+ * 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.Order;
+import org.traccar.storage.query.Request;
+
+import javax.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;
+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;
+
+ @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 ");
+ 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()));
+ try {
+ 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());
+ }
+ return builder.executeQuery(clazz);
+ } catch (SQLException e) {
+ throw new StorageException(e);
+ }
+ }
+
+ @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(getStorageName(entity.getClass()));
+ query.append("(");
+ query.append(formatColumns(columns, c -> c));
+ query.append(") VALUES (");
+ query.append(formatColumns(columns, c -> ':' + c));
+ query.append(")");
+ try {
+ QueryBuilder builder = QueryBuilder.create(config, dataSource, objectMapper, query.toString(), true);
+ builder.setObject(entity, columns);
+ return builder.executeUpdate();
+ } catch (SQLException e) {
+ throw new StorageException(e);
+ }
+ }
+
+ @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(getStorageName(entity.getClass()));
+ query.append(" SET ");
+ query.append(formatColumns(columns, c -> c + " = :" + c));
+ query.append(formatCondition(request.getCondition()));
+ try {
+ 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());
+ }
+ builder.executeUpdate();
+ } catch (SQLException e) {
+ throw new StorageException(e);
+ }
+ }
+
+ @Override
+ public void removeObject(Class<?> clazz, Request request) throws StorageException {
+ StringBuilder query = new StringBuilder("DELETE FROM ");
+ query.append(getStorageName(clazz));
+ query.append(formatCondition(request.getCondition()));
+ try {
+ 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());
+ }
+ builder.executeUpdate();
+ } catch (SQLException e) {
+ throw new StorageException(e);
+ }
+ }
+
+ @Override
+ 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(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);
+ }
+ }
+
+ @Override
+ public void addPermission(Permission permission) throws StorageException {
+ StringBuilder query = new StringBuilder("INSERT INTO ");
+ query.append(permission.getStorageName());
+ query.append(" VALUES (");
+ query.append(permission.get().keySet().stream().map(key -> ':' + key).collect(Collectors.joining(", ")));
+ query.append(")");
+ try {
+ QueryBuilder builder = QueryBuilder.create(config, dataSource, objectMapper, query.toString(), true);
+ for (var entry : permission.get().entrySet()) {
+ builder.setLong(entry.getKey(), entry.getValue());
+ }
+ builder.executeUpdate();
+ } catch (SQLException e) {
+ throw new StorageException(e);
+ }
+ }
+
+ @Override
+ public void removePermission(Permission permission) throws StorageException {
+ StringBuilder query = new StringBuilder("DELETE FROM ");
+ query.append(permission.getStorageName());
+ query.append(" WHERE ");
+ query.append(permission
+ .get().keySet().stream().map(key -> key + " = :" + key).collect(Collectors.joining(" AND ")));
+ try {
+ QueryBuilder builder = QueryBuilder.create(config, dataSource, objectMapper, query.toString(), true);
+ for (var entry : permission.get().entrySet()) {
+ builder.setLong(entry.getKey(), entry.getValue());
+ }
+ builder.executeUpdate();
+ } catch (SQLException e) {
+ throw new StorageException(e);
+ }
+ }
+
+ private String getStorageName(Class<?> clazz) throws StorageException {
+ StorageName storageName = clazz.getAnnotation(StorageName.class);
+ if (storageName == null) {
+ throw new StorageException("StorageName annotation is missing");
+ }
+ return storageName.value();
+ }
+
+ private Map<String, Object> getConditionVariables(Condition genericCondition) {
+ Map<String, Object> results = new HashMap<>();
+ if (genericCondition instanceof Condition.Compare) {
+ var condition = (Condition.Compare) genericCondition;
+ if (condition.getValue() != null) {
+ results.put(condition.getVariable(), condition.getValue());
+ }
+ } else if (genericCondition instanceof Condition.Between) {
+ var condition = (Condition.Between) genericCondition;
+ results.put(condition.getFromVariable(), condition.getFromValue());
+ results.put(condition.getToVariable(), condition.getToValue());
+ } else if (genericCondition instanceof Condition.Binary) {
+ 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(List<String> columns, Function<String, String> mapper) {
+ return columns.stream().map(mapper).collect(Collectors.joining(", "));
+ }
+
+ private String formatCondition(Condition genericCondition) throws StorageException {
+ return formatCondition(genericCondition, true);
+ }
+
+ private String formatCondition(Condition genericCondition, boolean appendWhere) throws StorageException {
+ StringBuilder result = new StringBuilder();
+ if (genericCondition != null) {
+ if (appendWhere) {
+ result.append(" WHERE ");
+ }
+ if (genericCondition instanceof Condition.Compare) {
+
+ var condition = (Condition.Compare) genericCondition;
+ result.append(condition.getColumn());
+ result.append(" ");
+ result.append(condition.getOperator());
+ result.append(" :");
+ result.append(condition.getVariable());
+
+ } else if (genericCondition instanceof Condition.Between) {
+
+ var condition = (Condition.Between) genericCondition;
+ result.append(condition.getColumn());
+ result.append(" BETWEEN :");
+ result.append(condition.getFromVariable());
+ result.append(" AND :");
+ result.append(condition.getToVariable());
+
+ } else if (genericCondition instanceof Condition.Binary) {
+
+ 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();
+ }
+
+ private String formatOrder(Order order) {
+ StringBuilder result = new StringBuilder();
+ if (order != null) {
+ result.append(" ORDER BY ");
+ result.append(order.getColumn());
+ 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 formatPermissionQuery(Condition.Permission condition) throws StorageException {
+ StringBuilder result = new StringBuilder();
+
+ 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
new file mode 100644
index 000000000..f19897ff8
--- /dev/null
+++ b/src/main/java/org/traccar/storage/MemoryStorage.java
@@ -0,0 +1,79 @@
+/*
+ * 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.Pair;
+import org.traccar.model.Permission;
+import org.traccar.storage.query.Request;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class MemoryStorage extends Storage {
+
+ private final Map<Pair<Class<?>, Class<?>>, Set<Pair<Long, Long>>> permissions = new HashMap<>();
+
+ @Override
+ public <T> List<T> getObjects(Class<T> clazz, Request request) {
+ return null;
+ }
+
+ @Override
+ public <T> long addObject(T entity, Request request) {
+ return 0;
+ }
+
+ @Override
+ public <T> void updateObject(T entity, Request request) {
+ }
+
+ @Override
+ public void removeObject(Class<?> clazz, Request request) {
+ }
+
+ private Set<Pair<Long, Long>> getPermissionsSet(Class<?> ownerClass, Class<?> propertyClass) {
+ return permissions.computeIfAbsent(new Pair<>(ownerClass, propertyClass), k -> new HashSet<>());
+ }
+
+ @Override
+ 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());
+ }
+
+ @Override
+ public void addPermission(Permission permission) {
+ getPermissionsSet(permission.getOwnerClass(), permission.getPropertyClass())
+ .add(new Pair<>(permission.getOwnerId(), permission.getPropertyId()));
+ }
+
+ @Override
+ public void removePermission(Permission permission) {
+ getPermissionsSet(permission.getOwnerClass(), permission.getPropertyClass())
+ .remove(new Pair<>(permission.getOwnerId(), permission.getPropertyId()));
+ }
+
+}
diff --git a/src/main/java/org/traccar/database/QueryBuilder.java b/src/main/java/org/traccar/storage/QueryBuilder.java
index 396cbf562..2f4c07406 100644
--- a/src/main/java/org/traccar/database/QueryBuilder.java
+++ b/src/main/java/org/traccar/storage/QueryBuilder.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.
@@ -13,12 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.database;
+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;
@@ -33,7 +35,6 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.sql.Types;
-import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
@@ -41,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) {
@@ -126,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) {
@@ -255,36 +266,49 @@ public final class QueryBuilder {
return this;
}
- public QueryBuilder setObject(Object object) throws SQLException {
-
- Method[] methods = object.getClass().getMethods();
+ public QueryBuilder setValue(String name, Object value) throws SQLException {
+ if (value instanceof Boolean) {
+ setBoolean(name, (Boolean) value);
+ } else if (value instanceof Integer) {
+ setInteger(name, (Integer) value);
+ } else if (value instanceof Long) {
+ setLong(name, (Long) value);
+ } else if (value instanceof Double) {
+ setDouble(name, (Double) value);
+ } else if (value instanceof String) {
+ setString(name, (String) value);
+ } else if (value instanceof Date) {
+ setDate(name, (Date) value);
+ }
+ return this;
+ }
- for (Method method : methods) {
- if (method.getName().startsWith("get") && method.getParameterTypes().length == 0
- && !method.isAnnotationPresent(QueryIgnore.class)) {
- 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;
@@ -294,15 +318,6 @@ public final class QueryBuilder {
void process(T object, ResultSet resultSet) throws SQLException;
}
- public <T> T executeQuerySingle(Class<T> clazz) throws SQLException {
- Collection<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) {
@@ -371,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);
}
@@ -380,13 +395,21 @@ public final class QueryBuilder {
}
}
- public <T> Collection<T> executeQuery(Class<T> clazz) throws SQLException {
+ 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<>();
if (query != null) {
try {
+ logQuery();
+
try (ResultSet resultSet = statement.executeQuery()) {
ResultSetMetaData resultMetaData = resultSet.getMetaData();
@@ -396,8 +419,7 @@ public final class QueryBuilder {
Method[] methods = clazz.getMethods();
for (final Method method : methods) {
- if (method.getName().startsWith("set") && method.getParameterTypes().length == 1
- && !method.isAnnotationPresent(QueryIgnore.class)) {
+ if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) {
final String name = method.getName().substring(3);
@@ -443,6 +465,7 @@ public final class QueryBuilder {
if (query != null) {
try {
+ logQuery();
statement.execute();
if (returnGeneratedKeys) {
ResultSet resultSet = statement.getGeneratedKeys();
@@ -458,10 +481,11 @@ public final class QueryBuilder {
return 0;
}
- public Collection<Permission> executePermissionsQuery() throws SQLException, ClassNotFoundException {
+ public List<Permission> executePermissionsQuery() throws SQLException {
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/database/QueryIgnore.java b/src/main/java/org/traccar/storage/QueryIgnore.java
index ac835cf2f..553d4b9fc 100644
--- a/src/main/java/org/traccar/database/QueryIgnore.java
+++ b/src/main/java/org/traccar/storage/QueryIgnore.java
@@ -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.storage;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
diff --git a/src/main/java/org/traccar/storage/Storage.java b/src/main/java/org/traccar/storage/Storage.java
new file mode 100644
index 000000000..55f5c22c0
--- /dev/null
+++ b/src/main/java/org/traccar/storage/Storage.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.storage;
+
+import org.traccar.model.BaseModel;
+import org.traccar.model.Permission;
+import org.traccar.storage.query.Request;
+
+import java.util.List;
+
+public abstract class Storage {
+
+ public abstract <T> List<T> getObjects(Class<T> clazz, Request request) throws StorageException;
+
+ public abstract <T> long addObject(T entity, Request request) throws StorageException;
+
+ public abstract <T> void updateObject(T entity, Request request) throws StorageException;
+
+ public abstract void removeObject(Class<?> clazz, Request request) throws StorageException;
+
+ public abstract List<Permission> getPermissions(
+ 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
new file mode 100644
index 000000000..3f066cae6
--- /dev/null
+++ b/src/main/java/org/traccar/storage/StorageException.java
@@ -0,0 +1,32 @@
+/*
+ * 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 {
+
+ public StorageException(String message) {
+ super(message);
+ }
+
+ public StorageException(Throwable cause) {
+ super(cause);
+ }
+
+ public StorageException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/src/main/java/org/traccar/database/QueryExtended.java b/src/main/java/org/traccar/storage/StorageName.java
index 07bc2c211..bf824c333 100644
--- a/src/main/java/org/traccar/database/QueryExtended.java
+++ b/src/main/java/org/traccar/storage/StorageName.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,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.database;
+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)
+@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
-public @interface QueryExtended {
+public @interface StorageName {
+ String value();
}
diff --git a/src/main/java/org/traccar/storage/query/Columns.java b/src/main/java/org/traccar/storage/query/Columns.java
new file mode 100644
index 000000000..a00400b36
--- /dev/null
+++ b/src/main/java/org/traccar/storage/query/Columns.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.storage.query;
+
+import org.traccar.storage.QueryIgnore;
+
+import java.beans.Introspector;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public abstract class Columns {
+
+ public abstract List<String> getColumns(Class<?> clazz, String type);
+
+ protected List<String> getAllColumns(Class<?> clazz, String type) {
+ List<String> columns = new LinkedList<>();
+ Method[] methods = clazz.getMethods();
+ for (Method method : methods) {
+ int parameterCount = type.equals("set") ? 1 : 0;
+ if (method.getName().startsWith(type) && method.getParameterTypes().length == parameterCount
+ && !method.isAnnotationPresent(QueryIgnore.class)
+ && !method.getName().equals("getClass")) {
+ columns.add(Introspector.decapitalize(method.getName().substring(3)));
+ }
+ }
+ return columns;
+ }
+
+ public static class All extends Columns {
+ @Override
+ public List<String> getColumns(Class<?> clazz, String type) {
+ return getAllColumns(clazz, type);
+ }
+ }
+
+ public static class Include extends Columns {
+ private final List<String> columns;
+
+ public Include(String... columns) {
+ this.columns = Arrays.stream(columns).collect(Collectors.toList());
+ }
+
+ @Override
+ public List<String> getColumns(Class<?> clazz, String type) {
+ return columns;
+ }
+ }
+
+ public static class Exclude extends Columns {
+ private final Set<String> columns;
+
+ public Exclude(String... columns) {
+ this.columns = Arrays.stream(columns).collect(Collectors.toSet());
+ }
+
+ @Override
+ public List<String> getColumns(Class<?> clazz, String type) {
+ return getAllColumns(clazz, type).stream()
+ .filter(column -> !columns.contains(column))
+ .collect(Collectors.toList());
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/storage/query/Condition.java b/src/main/java/org/traccar/storage/query/Condition.java
new file mode 100644
index 000000000..08b199052
--- /dev/null
+++ b/src/main/java/org/traccar/storage/query/Condition.java
@@ -0,0 +1,211 @@
+/*
+ * 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 {
+
+ 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;
+ }
+
+ class Equals extends Compare {
+ public Equals(String column, Object value) {
+ super(column, "=", column, value);
+ }
+ }
+
+ class Compare implements Condition {
+ private final String column;
+ private final String operator;
+ private final String variable;
+ private final Object value;
+
+ public Compare(String column, String operator, String variable, Object value) {
+ this.column = column;
+ this.operator = operator;
+ this.variable = variable;
+ this.value = value;
+ }
+
+ public String getColumn() {
+ return column;
+ }
+
+ public String getOperator() {
+ return operator;
+ }
+
+ public String getVariable() {
+ return variable;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+ }
+
+ class Between implements Condition {
+ private final String column;
+ private final String fromVariable;
+ private final Object fromValue;
+ private final String toVariable;
+ private final Object toValue;
+
+ public Between(String column, String fromVariable, Object fromValue, String toVariable, Object toValue) {
+ this.column = column;
+ this.fromVariable = fromVariable;
+ this.fromValue = fromValue;
+ this.toVariable = toVariable;
+ this.toValue = toValue;
+ }
+
+ public String getColumn() {
+ return column;
+ }
+
+ public String getFromVariable() {
+ return fromVariable;
+ }
+
+ public Object getFromValue() {
+ return fromValue;
+ }
+
+ public String getToVariable() {
+ return toVariable;
+ }
+
+ public Object getToValue() {
+ return toValue;
+ }
+ }
+
+ class Or extends Binary {
+ public Or(Condition first, Condition second) {
+ super(first, second, "OR");
+ }
+ }
+
+ class And extends Binary {
+ public And(Condition first, Condition second) {
+ super(first, second, "AND");
+ }
+ }
+
+ class Binary implements Condition {
+ private final Condition first;
+ private final Condition second;
+ private final String operator;
+
+ public Binary(Condition first, Condition second, String operator) {
+ this.first = first;
+ this.second = second;
+ this.operator = operator;
+ }
+
+ public Condition getFirst() {
+ return first;
+ }
+
+ public Condition getSecond() {
+ return second;
+ }
+
+ public String getOperator() {
+ return operator;
+ }
+ }
+
+ 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/database/OrderManager.java b/src/main/java/org/traccar/storage/query/Limit.java
index c3253e52f..9673e5426 100644
--- a/src/main/java/org/traccar/database/OrderManager.java
+++ b/src/main/java/org/traccar/storage/query/Limit.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,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.traccar.database;
+package org.traccar.storage.query;
-import org.traccar.model.Order;
+public class Limit {
-public class OrderManager extends ExtendedObjectManager<Order> {
+ private final int value;
- public OrderManager(DataManager dataManager) {
- super(dataManager, Order.class);
+ public Limit(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
}
}
diff --git a/src/main/java/org/traccar/storage/query/Order.java b/src/main/java/org/traccar/storage/query/Order.java
new file mode 100644
index 000000000..f10970381
--- /dev/null
+++ b/src/main/java/org/traccar/storage/query/Order.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.storage.query;
+
+public class Order {
+
+ private final String column;
+ private final boolean descending;
+ private final int limit;
+
+ public Order(String column) {
+ this(column, false, 0);
+ }
+
+ public Order(String column, boolean descending, int limit) {
+ this.column = column;
+ this.descending = descending;
+ this.limit = limit;
+ }
+
+ public String getColumn() {
+ return column;
+ }
+
+ public boolean getDescending() {
+ 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
new file mode 100644
index 000000000..b9c2c963c
--- /dev/null
+++ b/src/main/java/org/traccar/storage/query/Request.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.storage.query;
+
+public class Request {
+
+ private final Columns columns;
+ private final Condition condition;
+ private final Order order;
+
+ public Request(Columns columns) {
+ this(columns, null, null);
+ }
+
+ public Request(Condition condition) {
+ this(null, condition, null);
+ }
+
+ public Request(Columns columns, Condition condition) {
+ this(columns, condition, null);
+ }
+
+ public Request(Columns columns, Order order) {
+ this(columns, null, order);
+ }
+
+ public Request(Columns columns, Condition condition, Order order) {
+ this.columns = columns;
+ this.condition = condition;
+ this.order = order;
+ }
+
+ public Columns getColumns() {
+ return columns;
+ }
+
+ public Condition getCondition() {
+ return condition;
+ }
+
+ public Order getOrder() {
+ return order;
+ }
+
+}
diff --git a/src/main/java/org/traccar/web/ConsoleServlet.java b/src/main/java/org/traccar/web/ConsoleServlet.java
index 0f3dcd8fd..902a4f7a9 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 - 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 org.h2.server.web.ConnectionInfo;
import org.h2.server.web.WebServlet;
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;
@@ -30,6 +30,12 @@ public class ConsoleServlet extends WebServlet {
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();
@@ -40,9 +46,9 @@ public class ConsoleServlet extends WebServlet {
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/ThrottlingFilter.java b/src/main/java/org/traccar/web/ThrottlingFilter.java
new file mode 100644
index 000000000..054af652f
--- /dev/null
+++ b/src/main/java/org/traccar/web/ThrottlingFilter.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.web;
+
+import org.eclipse.jetty.servlets.DoSFilter;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import javax.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));
+ }
+ }
+
+ @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..14d9d3dbc
--- /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 javax.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..0722c5d1e
--- /dev/null
+++ b/src/main/java/org/traccar/web/WebModule.java
@@ -0,0 +1,30 @@
+/*
+ * 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 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("/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 604edfedc..79d19cc9b 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 - 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.
@@ -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;
@@ -40,37 +42,42 @@ import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.api.DateParameterConverterProvider;
-import org.traccar.config.Config;
-import org.traccar.api.AsyncSocketServlet;
+import org.traccar.LifecycleObject;
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.SecurityRequestFilter;
import org.traccar.api.resource.ServerResource;
+import org.traccar.api.security.SecurityRequestFilter;
+import org.traccar.config.Config;
import org.traccar.config.Keys;
+import org.traccar.helper.ObjectMapperContextResolver;
import javax.servlet.DispatcherType;
import javax.servlet.ServletException;
import javax.servlet.SessionCookieConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.net.InetSocketAddress;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.EnumSet;
-public class WebServer {
+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) {
@@ -78,39 +85,42 @@ public class WebServer {
} 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
protected void handleErrorPage(
HttpServletRequest request, Writer writer, int code, String message) throws IOException {
- writer.write("<!DOCTYPE><html><head><title>Error</title></head><html><body>"
- + code + " - " + HttpStatus.getMessage(code) + "</body></html>");
+ Path index = Paths.get(config.getString(Keys.WEB_PATH), "index.html");
+ if (code == HttpStatus.NOT_FOUND_404
+ && !request.getPathInfo().startsWith("/api/") && Files.exists(index)) {
+ writer.write(Files.readString(index));
+ } else {
+ writer.write("<!DOCTYPE><html><head><title>Error</title></head><html><body>"
+ + code + " - " + HttpStatus.getMessage(code) + "</body></html>");
+ }
}
});
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));
@@ -119,7 +129,7 @@ public class WebServer {
}
}
- 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() {
@@ -132,14 +142,14 @@ public class WebServer {
}
}
};
- 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) {
+ private void initWebApp(ServletContextHandler servletHandler) {
ServletHolder servletHolder = new ServletHolder(DefaultServlet.class);
servletHolder.setInitParameter("resourceBase", new File(config.getString(Keys.WEB_PATH)).getAbsolutePath());
servletHolder.setInitParameter("dirAllowed", "false");
@@ -155,10 +165,7 @@ public class WebServer {
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);
@@ -166,21 +173,27 @@ public class WebServer {
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());
+ 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,20 +227,14 @@ public class WebServer {
}
}
- public void start() {
- try {
- server.start();
- } catch (Exception error) {
- LOGGER.warn("Web server start failed", error);
- }
+ @Override
+ public void start() throws Exception {
+ server.start();
}
- public void stop() {
- try {
- server.stop();
- } catch (Exception error) {
- LOGGER.warn("Web server stop failed", error);
- }
+ @Override
+ 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/test/java/org/traccar/BaseTest.java b/src/test/java/org/traccar/BaseTest.java
index 0b2c616ce..c784150dd 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())).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 c40a15dcc..5e37f44b9 100644
--- a/src/test/java/org/traccar/ProtocolTest.java
+++ b/src/test/java/org/traccar/ProtocolTest.java
@@ -4,14 +4,17 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
+import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
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;
@@ -89,6 +92,10 @@ public class ProtocolTest extends BaseTest {
return new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, method, url, Unpooled.buffer(), headers, new DefaultHttpHeaders());
}
+ protected DefaultFullHttpResponse response(ByteBuf data) {
+ return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, data);
+ }
+
protected void verifyNotNull(BaseProtocolDecoder decoder, Object object) throws Exception {
assertNotNull(decoder.decode(null, null, object));
}
@@ -304,12 +311,20 @@ 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})"));
+ }
}
}
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..def67ff76 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.Test;
+import org.traccar.model.Calendar;
+
import java.io.IOException;
import java.sql.SQLException;
import java.text.DateFormat;
@@ -7,11 +11,6 @@ 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;
public class CalendarTest {
diff --git a/src/test/java/org/traccar/config/ConfigTest.java b/src/test/java/org/traccar/config/ConfigTest.java
index 13d0ffb04..8ba6dace6 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;
public class ConfigTest {
diff --git a/src/test/java/org/traccar/database/DataManagerTest.java b/src/test/java/org/traccar/database/DataManagerTest.java
deleted file mode 100644
index 23043e96e..000000000
--- a/src/test/java/org/traccar/database/DataManagerTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.traccar.database;
-
-import org.junit.Test;
-import org.traccar.model.Attribute;
-import org.traccar.model.Device;
-import org.traccar.model.Driver;
-import org.traccar.model.Geofence;
-import org.traccar.model.Group;
-import org.traccar.model.ManagedUser;
-import org.traccar.model.Position;
-import org.traccar.model.User;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class DataManagerTest {
-
- @Test
- public void constructObjectQuery() {
- assertEquals("SELECT * FROM tc_users",
- DataManager.constructObjectQuery(DataManager.ACTION_SELECT_ALL, User.class, false));
- assertEquals("DELETE FROM tc_groups WHERE id = :id",
- DataManager.constructObjectQuery(DataManager.ACTION_DELETE, Group.class, false));
- assertEquals("SELECT * FROM tc_positions WHERE id = :id",
- DataManager.constructObjectQuery(DataManager.ACTION_SELECT, Position.class, false));
-
- String insertDevice = DataManager.constructObjectQuery(DataManager.ACTION_INSERT, Device.class, false);
- assertFalse(insertDevice.contains("class"));
- assertFalse(insertDevice.contains("id"));
- assertFalse(insertDevice.contains("status"));
- assertFalse(insertDevice.contains("geofenceIds"));
-
- String updateDeviceStatus = DataManager.constructObjectQuery("update", Device.class, true);
- assertTrue(updateDeviceStatus.contains("lastUpdate"));
-
- String updateUser = DataManager.constructObjectQuery(DataManager.ACTION_UPDATE, User.class, false);
- assertFalse(updateUser.contains("class"));
- assertFalse(updateUser.contains("password"));
- assertFalse(updateUser.contains("salt"));
-
- String updateUserPassword = DataManager.constructObjectQuery(DataManager.ACTION_UPDATE, User.class, true);
- assertFalse(updateUserPassword.contains("name"));
- assertTrue(updateUserPassword.contains("hashedPassword"));
- assertTrue(updateUserPassword.contains("salt"));
-
- String insertPosition = DataManager.constructObjectQuery(DataManager.ACTION_INSERT, Position.class, false);
- assertFalse(insertPosition.contains("type"));
- assertFalse(insertPosition.contains("outdated"));
-
- }
-
- @Test
- public void constructPermissionsQuery() {
- assertEquals("SELECT userId, deviceId FROM tc_user_device",
- DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, User.class, Device.class));
-
- assertEquals("SELECT userId, managedUserId FROM tc_user_user",
- DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, User.class, ManagedUser.class));
-
- assertEquals("SELECT deviceId, driverId FROM tc_device_driver",
- DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, Device.class, Driver.class));
-
- assertEquals("SELECT groupId, geofenceId FROM tc_group_geofence",
- DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, Group.class, Geofence.class));
-
- assertEquals("INSERT INTO tc_user_device (userId, deviceId) VALUES (:userId, :deviceId)",
- DataManager.constructPermissionQuery(DataManager.ACTION_INSERT, User.class, Device.class));
-
- assertEquals("DELETE FROM tc_user_user WHERE userId = :userId AND managedUserId = :managedUserId",
- DataManager.constructPermissionQuery(DataManager.ACTION_DELETE, User.class, ManagedUser.class));
-
- assertEquals("INSERT INTO tc_device_geofence (deviceId, geofenceId) VALUES (:deviceId, :geofenceId)",
- DataManager.constructPermissionQuery(DataManager.ACTION_INSERT, Device.class, Geofence.class));
-
- assertEquals("DELETE FROM tc_group_attribute WHERE groupId = :groupId AND attributeId = :attributeId",
- DataManager.constructPermissionQuery(DataManager.ACTION_DELETE, Group.class, Attribute.class));
-
- }
-
-}
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..522958052
--- /dev/null
+++ b/src/test/java/org/traccar/forward/PositionForwarderUrlTest.java
@@ -0,0 +1,42 @@
+package org.traccar.forward;
+
+import org.junit.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.Assert.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/GeocoderTest.java b/src/test/java/org/traccar/geocoder/GeocoderTest.java
index 380980d2b..ff33b1f1c 100644
--- a/src/test/java/org/traccar/geocoder/GeocoderTest.java
+++ b/src/test/java/org/traccar/geocoder/GeocoderTest.java
@@ -1,10 +1,12 @@
package org.traccar.geocoder;
-import java.util.Locale;
-
import org.junit.Ignore;
import org.junit.Test;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import java.util.Locale;
+
import static org.junit.Assert.assertEquals;
public class GeocoderTest {
@@ -13,10 +15,12 @@ public class GeocoderTest {
Locale.setDefault(Locale.US);
}
+ private final Client client = ClientBuilder.newClient();
+
@Ignore
@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);
}
@@ -24,7 +28,7 @@ public class GeocoderTest {
@Ignore
@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);
}
@@ -32,7 +36,7 @@ public class GeocoderTest {
@Ignore
@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);
}
@@ -41,7 +45,7 @@ public class GeocoderTest {
@Test
public void testOpenCage() {
Geocoder geocoder = new OpenCageGeocoder(
- "http://api.opencagedata.com/geocode/v1", "SECRET", 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);
}
@@ -49,7 +53,7 @@ public class GeocoderTest {
@Ignore
@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);
}
@@ -57,7 +61,7 @@ public class GeocoderTest {
@Ignore
@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);
}
@@ -65,7 +69,7 @@ public class GeocoderTest {
@Ignore
@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);
}
@@ -73,7 +77,7 @@ public class GeocoderTest {
@Ignore
@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);
}
@@ -81,7 +85,7 @@ public class GeocoderTest {
@Ignore
@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);
}
@@ -89,7 +93,7 @@ public class GeocoderTest {
@Ignore
@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);
}
@@ -97,7 +101,7 @@ public class GeocoderTest {
@Ignore
@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);
}
@@ -105,9 +109,17 @@ public class GeocoderTest {
@Ignore
@Test
public void testMapTiler() {
- Geocoder geocoder = new MapTilerGeocoder("mnbnwLErpdspq13f0kC6", 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
+ @Test
+ public void testGeoapify() {
+ 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..9a02cec76 100644
--- a/src/test/java/org/traccar/geofence/GeofenceCircleTest.java
+++ b/src/test/java/org/traccar/geofence/GeofenceCircleTest.java
@@ -1,10 +1,11 @@
package org.traccar.geofence;
-import java.text.ParseException;
-
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;
public class GeofenceCircleTest {
@@ -12,17 +13,15 @@ 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..5baecd771 100644
--- a/src/test/java/org/traccar/geofence/GeofencePolygonTest.java
+++ b/src/test/java/org/traccar/geofence/GeofencePolygonTest.java
@@ -1,9 +1,9 @@
package org.traccar.geofence;
-import java.text.ParseException;
-
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;
@@ -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..b7ee14510 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.Test;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.model.Geofence;
+
+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.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..876b6b688 100644
--- a/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java
+++ b/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java
@@ -6,19 +6,20 @@ import org.traccar.BaseTest;
import org.traccar.model.CellTower;
import org.traccar.model.Network;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
public class GeolocationProviderTest extends BaseTest {
+ private final Client client = ClientBuilder.newClient();
+
@Ignore
@Test
- public void test() throws Exception {
- testLocationProvider();
- }
-
- public void testLocationProvider() throws Exception {
- MozillaGeolocationProvider provider = new MozillaGeolocationProvider(null);
+ 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..2668c4f14 100644
--- a/src/test/java/org/traccar/handler/ComputedAttributesTest.java
+++ b/src/test/java/org/traccar/handler/ComputedAttributesTest.java
@@ -1,12 +1,12 @@
package org.traccar.handler;
-import java.util.Date;
-
import org.junit.Test;
import org.traccar.config.Config;
import org.traccar.model.Attribute;
import org.traccar.model.Position;
+import java.util.Date;
+
import static org.junit.Assert.assertEquals;
public class ComputedAttributesTest {
@@ -14,7 +14,7 @@ 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();
diff --git a/src/test/java/org/traccar/handler/DistanceHandlerTest.java b/src/test/java/org/traccar/handler/DistanceHandlerTest.java
index f7c6e42cd..a18b14edd 100644
--- a/src/test/java/org/traccar/handler/DistanceHandlerTest.java
+++ b/src/test/java/org/traccar/handler/DistanceHandlerTest.java
@@ -3,15 +3,17 @@ package org.traccar.handler;
import org.junit.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.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..a1102da88 100644
--- a/src/test/java/org/traccar/handler/FilterHandlerTest.java
+++ b/src/test/java/org/traccar/handler/FilterHandlerTest.java
@@ -5,70 +5,81 @@ import org.junit.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.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);
+ 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);
+ passingHandler = new FilterHandler(config, cacheManager, null);
}
- private Position createPosition(
- long deviceId,
- Date time,
- boolean valid,
- double latitude,
- double longitude,
- double altitude,
- double speed,
- double course) {
+ @Before
+ 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);
+ }
+ 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));
- 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));
- 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));
@@ -78,7 +89,7 @@ public class FilterHandlerTest extends BaseTest {
@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));
diff --git a/src/test/java/org/traccar/handler/MotionHandlerTest.java b/src/test/java/org/traccar/handler/MotionHandlerTest.java
index 9e0859664..93fd16206 100644
--- a/src/test/java/org/traccar/handler/MotionHandlerTest.java
+++ b/src/test/java/org/traccar/handler/MotionHandlerTest.java
@@ -1,16 +1,22 @@
package org.traccar.handler;
-import static org.junit.Assert.assertEquals;
-
import org.junit.Test;
import org.traccar.model.Position;
+import org.traccar.reports.common.TripsConfig;
+
+import static org.junit.Assert.assertEquals;
+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);
+ TripsConfig tripsConfig = mock(TripsConfig.class);
+ when(tripsConfig.getSpeedThreshold()).thenReturn(0.01);
+
+ MotionHandler motionHandler = new MotionHandler(tripsConfig);
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..550a93da3 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.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.Assert.assertEquals;
+import static org.junit.Assert.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..4997a0e0f 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.traccar.BaseTest;
import org.traccar.model.Event;
import org.traccar.model.Position;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.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..84898bea0 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.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.Assert.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..aa2d0bbe3
--- /dev/null
+++ b/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java
@@ -0,0 +1,60 @@
+package org.traccar.handler.events;
+
+import org.junit.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.Assert.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..b77676dc8 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.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.Assert.assertEquals;
+import static org.junit.Assert.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, false, 0.01);
- 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, false, 0.01);
- 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, false, 0.01);
- 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..ee18ee052 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.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.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.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());
+ private void verifyState(OverspeedState overspeedState, boolean state, long geofenceId) {
+ assertEquals(state, overspeedState.getOverspeedState());
+ assertEquals(geofenceId, overspeedState.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 testOverspeedWithPosition(long geofenceId) throws ParseException {
+ OverspeedState state = new OverspeedState();
- if (notRepeat) {
- assertNull(deviceState.getOverspeedPosition());
- assertEquals(0, deviceState.getOverspeedGeofenceId());
- } else {
- assertNotNull(deviceState.getOverspeedPosition());
- assertEquals(geofenceId, deviceState.getOverspeedGeofenceId());
- }
+ OverspeedProcessor.updateState(state, position("2017-01-01 00:00:00", 50), 40, 15000, geofenceId);
+ assertNull(state.getEvent());
+ verifyState(state, true, geofenceId);
- nextPosition.setTime(date("2017-01-01 00:00:40"));
- nextPosition.setSpeed(30);
+ OverspeedProcessor.updateState(state, position("2017-01-01 00:00:10", 55), 40, 15000, geofenceId);
+ assertNull(state.getEvent());
- 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:20", 55), 40, 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);
- 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:30", 55), 40, 15000, geofenceId);
+ assertNull(state.getEvent());
+ 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);
-
- 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, 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/BufferUtilTest.java b/src/test/java/org/traccar/helper/BufferUtilTest.java
new file mode 100644
index 000000000..0196cef9d
--- /dev/null
+++ b/src/test/java/org/traccar/helper/BufferUtilTest.java
@@ -0,0 +1,41 @@
+package org.traccar.helper;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.Assert.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));
+ }
+
+ @Test
+ public void test2() {
+ ByteBuf buf = Unpooled.copiedBuffer("abcdef", StandardCharsets.US_ASCII);
+ buf.readerIndex(1);
+ buf.writerIndex(5);
+ assertEquals(2, BufferUtil.indexOf("cd", buf));
+ }
+
+ @Test
+ public void test3() {
+ ByteBuf buf = Unpooled.copiedBuffer("abcdefgh", StandardCharsets.US_ASCII);
+ buf.readerIndex(1);
+ buf.writerIndex(7);
+ assertEquals(3, BufferUtil.indexOf("de", buf, 2, 6));
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/AdmFrameDecoderTest.java b/src/test/java/org/traccar/protocol/AdmFrameDecoderTest.java
index 1682ca56d..02d42447e 100644
--- a/src/test/java/org/traccar/protocol/AdmFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AdmFrameDecoderTest.java
@@ -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..810d53bf7 100644
--- a/src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AdmProtocolDecoderTest.java
@@ -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..79f37c4e4 100644
--- a/src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/AdmProtocolEncoderTest.java
@@ -27,7 +27,7 @@ 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..36ea3d361 100644
--- a/src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AisProtocolDecoderTest.java
@@ -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..585e02c02 100644
--- a/src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AlematicsProtocolDecoderTest.java
@@ -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..5e0923e9c 100644
--- a/src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AnytrekProtocolDecoderTest.java
@@ -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..369c13115 100644
--- a/src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ApelProtocolDecoderTest.java
@@ -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..b055221f2 100644
--- a/src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AplicomFrameDecoderTest.java
@@ -10,7 +10,7 @@ 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..4b25830f8 100644
--- a/src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AplicomProtocolDecoderTest.java
@@ -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..e821c9dba 100644
--- a/src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AppelloProtocolDecoderTest.java
@@ -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..38c5d3b6d 100644
--- a/src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AquilaProtocolDecoderTest.java
@@ -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..fd65ce585 100644
--- a/src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Ardi01ProtocolDecoderTest.java
@@ -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..b07dff150 100644
--- a/src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ArknavProtocolDecoderTest.java
@@ -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..9686c694b 100644
--- a/src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ArknavX8ProtocolDecoderTest.java
@@ -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
new file mode 100644
index 000000000..515f7f7b2
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/ArmoliProtocolDecoderTest.java
@@ -0,0 +1,36 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+import org.traccar.model.Position;
+
+public class ArmoliProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new ArmoliProtocolDecoder(null));
+
+ verifyAttribute(decoder, text(
+ "[M869867039550712160821153237N41.033508E029.2697032F00036000000410006B336FFFFG458563@A6D>04410C2482>03410F56>03412F19>0441210000>034130FF>0441313A7>03410D30>04411F01B6>0341048C>04410C1C98];"),
+ Position.KEY_RPM, 1830L);
+
+ verifyPosition(decoder, text(
+ "[M869867038698074210122125205N38.735641E035.4727751E003340000000C00000E9E07FF:106AG505283H60E]"));
+
+ verifyAttribute(decoder, text(
+ "[W869867038698074,O,1234,2657,1]"),
+ Position.KEY_RESULT, "O,1234,2657,1");
+
+ verifyNull(decoder, text(
+ "[Q010001088610010024363698990011101070608200,05XXXXXXXXX,10.49.182.53,C,1,20,19,0]"));
+
+ verifyPosition(decoder, text(
+ "[M860906041293587100122061310N40.792751E029.4313092801143000000010003513209FFGC18080H8DA#E209C4]"));
+
+ verifyNull(decoder, text(
+ "[L866104027971681]"));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java
index f2940de59..f96da5203 100644
--- a/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ArnaviBinaryProtocolDecoderTest.java
@@ -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..92ca5d2b0 100644
--- a/src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ArnaviFrameDecoderTest.java
@@ -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..e27367119 100644
--- a/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ArnaviTextProtocolDecoderTest.java
@@ -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..2d8798dff 100644
--- a/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AstraProtocolDecoderTest.java
@@ -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..773a8f7f5 100644
--- a/src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/At2000FrameDecoderTest.java
@@ -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..8c32289f1 100644
--- a/src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/At2000ProtocolDecoderTest.java
@@ -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..958814e53 100644
--- a/src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AtrackFrameDecoderTest.java
@@ -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..b6b09fc25 100644
--- a/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java
@@ -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"));
@@ -111,7 +111,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..368f7ed4c 100644
--- a/src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AuroProtocolDecoderTest.java
@@ -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..30152e94c 100644
--- a/src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AustinNbProtocolDecoderTest.java
@@ -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..8e17d5673 100644
--- a/src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AutoFonProtocolDecoderTest.java
@@ -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..7f837451c 100644
--- a/src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AutoGradeProtocolDecoderTest.java
@@ -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..51bbd0d8c 100644
--- a/src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AutoTrackProtocolDecoderTest.java
@@ -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..7f41d6b47 100644
--- a/src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/AvemaProtocolDecoderTest.java
@@ -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..1da432cea 100644
--- a/src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Avl301ProtocolDecoderTest.java
@@ -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..ea3b38e7d 100644
--- a/src/test/java/org/traccar/protocol/B2316ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/B2316ProtocolDecoderTest.java
@@ -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..e5a442f2f
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/BceFrameDecoderTest.java
@@ -0,0 +1,26 @@
+package org.traccar.protocol;
+
+import org.junit.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..1d980b7e5 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.Ignore;
import org.junit.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
public class BceProtocolDecoderTest extends ProtocolTest {
+ @Ignore
+ @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..bfaa3ccd8 100644
--- a/src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/BceProtocolEncoderTest.java
@@ -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..2fb93f2a9 100644
--- a/src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/BlackKiteProtocolDecoderTest.java
@@ -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..1de542e24 100644
--- a/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/BlueProtocolDecoderTest.java
@@ -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..0a19eb3b0 100644
--- a/src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/BoxProtocolDecoderTest.java
@@ -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..ae4c47229
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/BstplProtocolDecoderTest.java
@@ -0,0 +1,21 @@
+package org.traccar.protocol;
+
+import org.junit.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 d6831c1cf..28876075d 100644
--- a/src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/C2stekProtocolDecoderTest.java
@@ -8,9 +8,15 @@ public class C2stekProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new C2stekProtocolDecoder(null);
+ var decoder = inject(new C2stekProtocolDecoder(null));
- verifyNull(decoder, text(
+ 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"));
+
+ verifyPosition(decoder, text(
"PA$863083038046613$D#181123#162850#1#+37.92684#+23.75933#0.62#200.1#0.0#3768#000#9#00#sz-w1001#B0907839$AP"));
verifyPosition(decoder, text(
diff --git a/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java
index 79d27e2ab..1a8431f23 100644
--- a/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CalAmpProtocolDecoderTest.java
@@ -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..d12d4aa9f 100644
--- a/src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CarTrackProtocolDecoderTest.java
@@ -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..71137cacf 100644
--- a/src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CarscopProtocolDecoderTest.java
@@ -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..1add623b7 100644
--- a/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CastelProtocolDecoderTest.java
@@ -9,7 +9,7 @@ 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(
"40403a00043231334744503230313830323133343300000000a002000001000001012011004d414c43333831434d4b4d353637313438c8fc0d0a"),
diff --git a/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java
index cdf6a7c3b..9b3a285da 100644
--- a/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/CastelProtocolEncoderTest.java
@@ -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..4022d688b 100644
--- a/src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CautelaProtocolDecoderTest.java
@@ -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..c266dd1f4 100644
--- a/src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CellocatorFrameDecoderTest.java
@@ -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..27cad39a3 100644
--- a/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CellocatorProtocolDecoderTest.java
@@ -2,13 +2,18 @@ package org.traccar.protocol;
import org.junit.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..bb5d4979d 100644
--- a/src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/CellocatorProtocolEncoderTest.java
@@ -11,7 +11,7 @@ public class CellocatorProtocolEncoderTest extends ProtocolTest {
@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..835ab5fe5 100644
--- a/src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CguardProtocolDecoderTest.java
@@ -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..0c1fc1f5d 100644
--- a/src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CityeasyProtocolDecoderTest.java
@@ -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..6da9856c8 100644
--- a/src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/CityeasyProtocolEncoderTest.java
@@ -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..6ac2ae01d 100644
--- a/src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ContinentalProtocolDecoderTest.java
@@ -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..f95bfb54d 100644
--- a/src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/CradlepointProtocolDecoderTest.java
@@ -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..c63775858 100644
--- a/src/test/java/org/traccar/protocol/DingtekFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DingtekFrameDecoderTest.java
@@ -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..7e5f68e05 100644
--- a/src/test/java/org/traccar/protocol/DingtekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DingtekProtocolDecoderTest.java
@@ -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..3faccd7ea 100644
--- a/src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DishaProtocolDecoderTest.java
@@ -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 bed56ba30..99760546f 100644
--- a/src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DmtHttpProtocolDecoderTest.java
@@ -9,7 +9,10 @@ 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}]}")));
verifyAttributes(decoder, request(HttpMethod.POST, "/",
buffer("{\"date\":\"2021-10-04T18:15:47Z\",\"device\":{\"sn\":\"403809\",\"prod\":85,\"rev\":1,\"fw\":\"1.12\",\"iccid\":\"89011702278483601922\",\"imei\":\"352656106127312\"},\"sqn\":40927,\"reason\":11,\"analogues\":[{\"id\":1,\"val\":4265},{\"id\":3,\"val\":3800},{\"id\":4,\"val\":12},{\"id\":5,\"val\":4251}],\"inputs\":1,\"outputs\":0,\"status\":137}")));
diff --git a/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java
index 82a4cd5ff..9c14a1ebe 100644
--- a/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DmtProtocolDecoderTest.java
@@ -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..b9e3da67d 100644
--- a/src/test/java/org/traccar/protocol/DolphinProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DolphinProtocolDecoderTest.java
@@ -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
new file mode 100644
index 000000000..7e3ec0706
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/Dsf22FrameDecoderTest.java
@@ -0,0 +1,23 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class Dsf22FrameDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new Dsf22FrameDecoder());
+
+ verifyFrame(
+ binary("4642000101A8EE5F0ECA5FF421B33F524E32610401"),
+ decoder.decode(null, null, binary("4642000101A8EE5F0ECA5FF421B33F524E32610401")));
+
+ verifyFrame(
+ binary("4642000103A8EE5F0ECA5FF421B33F524E326104010216600EFC92F421B63F524E366104013238600E1EBEF421B93F524E35610401"),
+ decoder.decode(null, null, binary("4642000103A8EE5F0ECA5FF421B33F524E326104010216600EFC92F421B63F524E366104013238600E1EBEF421B93F524E35610401")));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/Dsf22ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Dsf22ProtocolDecoderTest.java
new file mode 100644
index 000000000..2e52b950d
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/Dsf22ProtocolDecoderTest.java
@@ -0,0 +1,24 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class Dsf22ProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new Dsf22ProtocolDecoder(null));
+
+ verifyPositions(decoder, binary(
+ "4642a82d01c8f6aa1af1792c0c1411eb61001e0000"));
+
+ verifyPositions(decoder, binary(
+ "4642000101A8EE5F0ECA5FF421B33F524E32610401"));
+
+ verifyPositions(decoder, binary(
+ "4642000103A8EE5F0ECA5FF421B33F524E326104010216600EFC92F421B63F524E366104013238600E1EBEF421B93F524E35610401"));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/DualcamFrameDecoderTest.java b/src/test/java/org/traccar/protocol/DualcamFrameDecoderTest.java
index 46f32a8ae..f74a40d13 100644
--- a/src/test/java/org/traccar/protocol/DualcamFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DualcamFrameDecoderTest.java
@@ -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..a61f20c13 100644
--- a/src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DualcamProtocolDecoderTest.java
@@ -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..1cdd82664 100644
--- a/src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/DwayProtocolDecoderTest.java
@@ -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..ef319449e 100644
--- a/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java
@@ -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..1e1934435 100644
--- a/src/test/java/org/traccar/protocol/EasyTrackProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/EasyTrackProtocolEncoderTest.java
@@ -9,9 +9,9 @@ import static org.junit.Assert.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 d0c683abf..ec1467c09 100644
--- a/src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EelinkProtocolDecoderTest.java
@@ -9,11 +9,14 @@ 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"));
+ verifyPosition(decoder, binary(
+ "6767120056096661d38e0091fbf0aa3a0f8fa08500060051015f09002542e50e7ea6080101f90001304e304e0818390d000000c524c2ae0699102b00000000000115b0040504050000000014000000000000000000000000000002"));
+
verifyAttribute(decoder, binary(
"676714001500035f74a2940201360104591100a7160122250400"),
Position.KEY_ALARM, Position.ALARM_REMOVING);
@@ -42,9 +45,6 @@ public class EelinkProtocolDecoderTest extends ProtocolTest {
verifyPosition(decoder, binary(
"676714002414B05AD43A7D03026B92B10C395499FFD7000000000701CC00002495000014203604067B"));
- verifyNotNull(decoder, binary(
- "676714004F14B0E68CAFE58AA8E68AA5E8ADA621E5B9BFE4B89CE79C81E6B7B1E59CB3E5B882E58D97E5B1B1E58CBAE696B0E8A5BFE8B7AF3138EFBC88E8B79DE5AE87E998B3E5A4A7E58EA63230E7B1B3EFBC89"));
-
verifyPosition(decoder, binary(
"676780005a000001000000004c61743a4e33312e38333935352c4c6f6e3a5738322e36313334362c436f757273653a302e30302c53706565643a302e30306b6d2f682c4461746554696d653a323031372d31322d30322031313a32393a3433"));
diff --git a/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java
index 616ca0b52..380888843 100644
--- a/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/EelinkProtocolEncoderTest.java
@@ -7,15 +7,28 @@ 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..dde71d1e7 100644
--- a/src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EgtsFrameDecoderTest.java
@@ -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..0f5a40605 100644
--- a/src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EgtsProtocolDecoderTest.java
@@ -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..2d2a211c3 100644
--- a/src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EnforaProtocolDecoderTest.java
@@ -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..0134e8052 100644
--- a/src/test/java/org/traccar/protocol/EnnfuProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EnnfuProtocolDecoderTest.java
@@ -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
new file mode 100644
index 000000000..50db6c743
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java
@@ -0,0 +1,31 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class EnvotechProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new EnvotechProtocolDecoder(null));
+
+ verifyPosition(decoder, text(
+ "$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"));
+
+ verifyPosition(decoder, text(
+ "$80SLM,60,000F,F016109,290322100445,AF2463902,000406,0000,000,00018780,54000000'29032209493500406302S03966062E000348*E637"));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java
index d0d9e3c41..2d9b19b70 100644
--- a/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EsealProtocolDecoderTest.java
@@ -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..3ea8de5d6 100644
--- a/src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/EsealProtocolEncoderTest.java
@@ -11,7 +11,7 @@ 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..f808cd4a8 100644
--- a/src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EskyFrameDecoderTest.java
@@ -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..678007f5c 100644
--- a/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/EskyProtocolDecoderTest.java
@@ -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..36a26bbe3 100644
--- a/src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ExtremTracProtocolDecoderTest.java
@@ -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..417c49de5 100644
--- a/src/test/java/org/traccar/protocol/FifotrackFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FifotrackFrameDecoderTest.java
@@ -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..ec08b432c 100644
--- a/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FifotrackProtocolDecoderTest.java
@@ -9,7 +9,7 @@ public class FifotrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new FifotrackProtocolDecoder(null);
+ var decoder = inject(new FifotrackProtocolDecoder(null));
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..c3352f510 100644
--- a/src/test/java/org/traccar/protocol/FifotrackProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/FifotrackProtocolEncoderTest.java
@@ -11,7 +11,7 @@ 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..c794c9094 100644
--- a/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FlespiProtocolDecoderTest.java
@@ -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
new file mode 100644
index 000000000..ffb8eb3a9
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/FlexApiProtocolDecoderTest.java
@@ -0,0 +1,45 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class FlexApiProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ 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"));
+
+ verifyAttributes(decoder, text(
+ "${\"topic\":\"v1/VF3102021113001/gnss/info\",\"payload\":{\"gnss.ts\":1639713510,\"gnss.latitude\":30.587509,\"gnss.longitude\":104.053650,\"gnss.altitude\":391,\"gnss.speed\":0,\"gnss.heading\":0,\"gnss.hdop\":1.100000,\"gnss.fix\":4,\"gnss.num_sv\":10}}xx"));
+
+ verifyAttributes(decoder, text(
+ "${\"topic\":\"v1/VF3102021113001/cellular1/info\",\"payload\":{\"modem1.ts\":1639713510,\"modem1.imei\":\"863674047326655\",\"modem1.imsi\":\"\",\"modem1.iccid\":\"\",\"modem1.phone_num\":\"\",\"modem1.signal_lvl\":0,\"modem1.reg_status\":0,\"modem1.operator\":\"\",\"modem1.network\":0,\"modem1.lac\":\"\",\"modem1.cell_id\":\"\",\"modem1.rssi\":0,\"modem1.rsrp\":0,\"modem1.rsrq\":0,\"cellular1.status\":2,\"cellular1.ip\":\"0.0.0.0\",\"cellular1.netmask\":\"255.255.255.255\",\"cellular1.gateway\":\"0.0.0.0\",\"cellular1.dns1\":\"0.0.0.0\",\"cellular1.up_at\":602}}xx"));
+
+ verifyAttributes(decoder, text(
+ "${\"topic\":\"v1/VF3102029000003/obd/info\",\"payload\":{\"obd.ts\":1639037377,\"obd.speed\":211,\"obd.f_lvl\":50.196079,\"obd.mil\":0,\"obd.dtcs\":0,\"obd.rpm\":14531.250000,\"obd.e_load\":50.980392,\"obd.c_temp\":118,\"obd.o_temp\":56,\"obd.a_temp\":-40,\"obd.f_press\":48,\"obd.t_pos\":51.764706,\"obd.b_volt\":13.782000,\"obd.up_time\":2265,\"obd.m_dist\":4643,\"obd.m_time\":257,\"obd.d_dist\":200,\"obd.d_time\":771,\"obd.vin\":\"LFV3B28R8A3025310\",\"obd.f_rate\":10,\"obd.t_dist\":4843,\"obd.b_press\":101,\"obd.f_r_press\":48,\"obd.i_temp\":37,\"obd.i_press\":32,\"obd.r_torque\":4128,\"obd.a_torque\":2,\"obd.mf_mon\":1,\"obd.f_s_mon\":0,\"obd.c_c_mon\":0,\"obd.c_mon\":1,\"obd.e_s_mon\":1,\"obd.e_v_s_mon\":1,\"obd.o_s_mon\":1,\"obd.o_s_h_mon\":1}}xx"));
+
+ verifyAttributes(decoder, text(
+ "${\"topic\":\"v1/VF3102021111601/obd/info\",\"payload\":{\"obd.ts\":1637225390,\"obd.speed\":0,\"obd.f_lvl\":null,\"obd.odo\":0,\"obd.e_hours\":0,\"obd.ab_level\":null,\"obd.mil\":0,\"obd.dtcs\":null,\"obd.rpm\":0,\"obd.e_load\":null,\"obd.c_temp\":-40,\"obd.o_temp\":-273,\"obd.a_temp\":null,\"obd.f_press\":null,\"obd.t_pos\":0,\"obd.b_volt\":null,\"obd.up_time\":null,\"obd.m_dist\":null,\"obd.m_time\":null,\"obd.d_dist\":null,\"obd.d_time\":null,\"obd.vin\":\"NLVIN123456789ABC\",\"obd.brake\":0,\"obd.parking\":0,\"obd.s_w_angle\":null,\"obd.f_rate\":0,\"obd.f_econ\":0,\"obd.a_pos\":null,\"obd.t_dist\":0,\"obd.b_press\":null,\"obd.f_r_press\":null,\"obd.i_temp\":null,\"obd.i_press\":null,\"obd.r_torque\":null,\"obd.f_torque\":null,\"obd.max_avl_torque\":null,\"obd.a_torque\":-125,\"obd.d_e_f_vol\":null,\"obd.mf_mon\":null,\"obd.f_s_mon\":null,\"obd.c_c_mon\":null,\"obd.c_mon\":null,\"obd.h_c_mon\":null,\"obd.e_s_mon\":null,\"obd.s_a_s_mon\":null,\"obd.a_s_r_mon\":null,\"obd.e_g_s_mon\":null,\"obd.e_g_s_h_mon\":null,\"obd.e_v_s_mon\":null,\"obd.c_s_a_s_mon\":null,\"obd.b_p_c_s_mon\":null,\"obd.dpf_mon\":null,\"obd.n_c_mon\":null,\"obd.nmhc_mon\":null,\"obd.o_s_mon\":null,\"obd.o_s_h_mon\":null,\"obd.pf_mon\":null}}xx"));
+
+ verifyPosition(decoder, text(
+ "${\"topic\":\"v1/VF3102021111601/gnss/info\",\"payload\":{\"time\":1637225390,\"lat\":30.587942,\"log\":104.053543,\"gnss.altitude\":480.399994,\"gnss.speed\":0,\"gnss.heading\":0,\"gnss.hdop\":0.900000,\"gnss.fix\":4,\"gnss.num_sv\":11}}xx"));
+
+ verifyAttributes(decoder, text(
+ "${\"topic\":\"v1/VF3102021111601/motion/info\",\"payload\":{\"motion.ts\":1637225450,\"motion.ax\":0.009272,\"motion.ay\":0.278404,\"motion.az\":-0.941596,\"motion.gx\":0.420000,\"motion.gy\":-0.490000,\"motion.gz\":0.140000}}xx"));
+
+ verifyAttributes(decoder, text(
+ "${\"topic\":\"v1/VF3102021111601/sysinfo/info\",\"payload\":{\"sysinfo.ts\":1637224740,\"sysinfo.model_name\":\"310\",\"sysinfo.oem_name\":\"inhand\",\"sysinfo.serial_number\":\"VF3102021111601\",\"sysinfo.firmware_version\":\"VT3_V1.1.32\",\"sysinfo.product_number\":\"FQ58\",\"sysinfo.description\":\"www.inhand.com.cn\"}}xx"));
+
+ verifyAttributes(decoder, text(
+ "${\"topic\":\"v1/VF3102021111601/io/info\",\"payload\":{\"io.ts\":1637227722,\"io.AI1\":0,\"io.DI1\":1,\"io.DI2\":0,\"io.DI3\":0,\"io.DI4\":0,\"io.DI1_pullup\":0,\"io.DI2_pullup\":0,\"io.DI3_pullup\":0,\"io.DI4_pullup\":0,\"io.DO1\":0,\"io.DO2\":0,\"io.DO3\":0,\"io.IGT\":1}}xx"));
+
+ verifyAttributes(decoder, text(
+ "${\"topic\":\"v1/VF3102021111601/cellular1/info\",\"payload\":{\"modem1.ts\":1637225330,\"modem1.imei\":\"863674047324999\",\"modem1.imsi\":\"460111150414721\",\"modem1.iccid\":\"89860319482086580401\",\"modem1.phone_num\":\"\",\"modem1.signal_lvl\":25,\"modem1.reg_status\":1,\"modem1.operator\":\"46011\",\"modem1.network\":3,\"modem1.lac\":\"EA00\",\"modem1.cell_id\":\"E779B81\",\"modem1.rssi\":0,\"modem1.rsrp\":0,\"modem1.rsrq\":0,\"cellular1.status\":3,\"cellular1.ip\":\"10.136.143.193\",\"cellular1.netmask\":\"255.255.255.255\",\"cellular1.gateway\":\"10.64.64.64\",\"cellular1.dns1\":\"223.5.5.5\",\"cellular1.up_at\":450}}xx"));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java
index 3e988ba4f..ed44fc62e 100644
--- a/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FlexCommProtocolDecoderTest.java
@@ -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..6b289396d 100644
--- a/src/test/java/org/traccar/protocol/FlexibleReportProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FlexibleReportProtocolDecoderTest.java
@@ -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..6e5ebf4cf 100644
--- a/src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FlextrackProtocolDecoderTest.java
@@ -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..8e62c878e 100644
--- a/src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FoxProtocolDecoderTest.java
@@ -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..1163b4e04 100644
--- a/src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FreedomProtocolDecoderTest.java
@@ -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..a7ce042e5 100644
--- a/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FreematicsProtocolDecoderTest.java
@@ -8,7 +8,7 @@ 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(
"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..a101ef45d 100644
--- a/src/test/java/org/traccar/protocol/FutureWayFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FutureWayFrameDecoderTest.java
@@ -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..e529d5c90 100644
--- a/src/test/java/org/traccar/protocol/FutureWayProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/FutureWayProtocolDecoderTest.java
@@ -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..c8b4e35fe
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/G1rusProtocolDecoderTest.java
@@ -0,0 +1,18 @@
+package org.traccar.protocol;
+
+import org.junit.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..a5aba3513 100644
--- a/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GalileoFrameDecoderTest.java
@@ -10,7 +10,7 @@ public class GalileoFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GalileoFrameDecoder();
+ var decoder = inject(new GalileoFrameDecoder());
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..f676b1cc1 100644
--- a/src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GalileoProtocolDecoderTest.java
@@ -8,12 +8,18 @@ public class GalileoProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new GalileoProtocolDecoder(null);
+ var decoder = inject(new GalileoProtocolDecoder(null));
+
+ verifyNotNull(decoder, binary(
+ "01006501001c05cf1f8133303032333430363939303130313000004a000062d8f3ee03000b000f85402088970000000602003503333030323334303639393031303130100000207af3d862300cbe08ee00acfaf001330000760634b301350840090a416b2f42920e"));
verifyPositions(decoder, binary(
"011801018202130338363833343530333230343234323604640010a406207caa9f5b300c830a7901ca0ec802330000000034b802350540003e41703f422b1043234504004600e09000000000a000a100a200a300a400a500a600a700a800a900aa00ab00ac00ad00ae00af00b00000b10000b20000b30000b40000b50000b60000b70000b80000b90000c000000000c100000000c200000000c300000000c400c500c600c700c800c900ca00cb00cc00cd00ce00cf00d000d100d200d4d3140000d60000d70000d80000d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f300000000f400000000f500000000f600000000f700000000f800000000f9000000008960"));
verifyPositions(decoder, binary(
+ "01bf83043200101ee4209832bc62300549589302511aaa013300002e00342e02350440003b41b15d42d50e4326450e0046040050000051000052fc5c5300006100008b009000000000d400000000e201000000e376000000e4efce0100e53b590200e600000000e773000000e800000000e9a002d007ea140000d6021b00f8430220ac760000000000000000043200101de4201232bc62300549589302511aaa013300002e00342e02350440012b41b55d42d40e4326450e0046040050000051000052145d5300006100008b009000000000d400000000e201000000e376000000e4efce0100e53b590200e600000000e773000000e800000000e9a002d007ea140000d6021b00f8430220ac760000000000000000043200101ce4208e2ebc62300549589302511aaa013300002e00342e02350440013b41a95d42cd0e4325450f0046040050000051000052235d5300006100008b009000000000d400000000e201000000e376000000e4efce0100e53b590200e600000000e773000000e802000000e9a002d007ea140000d6021b00f8430220ac760000000000000000043200101be4208b2ebc62300549589302511aaa013300002e00342e02350440013b41a45d42cd0e432545090046040050000051000052115d5300006100008b009000000000d400000000e201000000e375000000e48ac90100e53a590200e673000000e773000000e806000000e9a002d007ea140000d6021b00f8430220ac760000000000000000043200101ae420642ebc62300549589302511aaa013300002e00342e02350440013b419f5d42cd0e4324450b00460600500000519313521c5d5300006100008b009000000000d400000000e201000000e300000000e406000000e5c5580200e673000000e700000000e801000000e9a002d007ea140000d6021b00f8430220ac7600000000000000000432001019e420632ebc62300549589302511aaa013300002e00342e02350440013b41725d42cd0e4324450b0046060050000051ab1352035d5300006100008b009000000000d400000000e201000000e300000000e406000000e5c5580200e673000000e700000000e8d6021b00e9a002d007ea140000d6021b00f8430220ac7600000000000000000432001018e4205c2ebc62300549589302511aaa013300002e00342e02350440013b41955d42cd0e4324450a00460400500000510000520b5d5300006100008b009000000000d400000000e201000000e30d000000e4a4350000e5c5580200e600000000e700000000e8d6021b00e9a002d007ea140000d6021b00f8430220ac76000000000000000099f3"));
+
+ verifyPositions(decoder, binary(
"017583018202120338363833343530333230363635373304520010384520c850975b300cc03a910107cbf9023365000607341300350640012a41236a4215104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d4993b0500d64100d70000d8be02d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f300000000018202120338363833343530333230363635373304520010394520c950975b300cab3a91010ecbf902336000be06341300350640012a41266a4216104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d49b3b0500d64100d70000d8bc02d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f3000000000182021203383638333435303332303636353733045200103a4520ca50975b300c953a910113cbf9023358008f06341300350640012a41206a4215104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d49e3b0500d64100d70000d8ba02d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f3000000000182021203383638333435303332303636353733045200103b45204251975b300c6d3a91011dcbf9023300008a06341300350640013a41726a4216104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d4a33b0500d64800d70000d80003d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f3000000000182021203383638333435303332303636353733045200103c4520bb51975b300c6d3a91011dcbf9023300008a06341300350640013a41816a4216104329450400460020500000510000520000530000540000550000c000000000c100000000c44bc500c6ffc700c800c900ca00cb00d4a33b0500d64800d70000d80003d90000da0000db00000000dc00000000dd00000000de00000000df00000000f000000000f100000000f200000000f300000000e007"));
verifyNull(decoder, binary(
diff --git a/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java
index b25100c48..29fe4cc94 100644
--- a/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/GalileoProtocolEncoderTest.java
@@ -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..bfb33de22 100644
--- a/src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GatorProtocolDecoderTest.java
@@ -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/GenxProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java
index 382c974ce..67a730f97 100644
--- a/src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GenxProtocolDecoderTest.java
@@ -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..31ae1d5e8 100644
--- a/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gl100ProtocolDecoderTest.java
@@ -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..cad70c35b 100644
--- a/src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gl200BinaryProtocolDecoderTest.java
@@ -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..51816222d 100644
--- a/src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gl200FrameDecoderTest.java
@@ -10,7 +10,7 @@ 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 8978f64e5..ef82a11a2 100644
--- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java
@@ -9,7 +9,22 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Gl200TextProtocolDecoder(null);
+ var decoder = inject(new Gl200TextProtocolDecoder(null));
+
+ 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$"));
+
+ verifyAttribute(decoder, buffer(
+ "+RESP:GTFRI,423031,866873025895726,,0,1,1,0,1,16,0.0,351,51.6,121.391063,31.164633,20181212072535,460,00,1877,DAE,00,3,85,20181212072535,002C$"),
+ Position.KEY_BATTERY_LEVEL, 85);
verifyAttributes(decoder, buffer(
"+RESP:GTINF,DC0103,865284049247079,gv600mg,21,89883070000007211665,22,0,11,12913,12917,4.26,0,1,,,20210216154607,1,79,,01,00,,,20210216104606,1EBE$"));
diff --git a/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java
index 3f5296f4b..e244a835d 100644
--- a/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GlobalSatProtocolDecoderTest.java
@@ -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..9001c4bf3 100644
--- a/src/test/java/org/traccar/protocol/GlobalSatProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/GlobalSatProtocolEncoderTest.java
@@ -9,9 +9,9 @@ import static org.junit.Assert.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..730d4bb60 100644
--- a/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java
@@ -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..592c2de91 100644
--- a/src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GnxProtocolDecoderTest.java
@@ -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..71ffbb587 100644
--- a/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GoSafeProtocolDecoderTest.java
@@ -9,7 +9,7 @@ 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#"));
diff --git a/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java
index bae187959..a6e3f2d69 100644
--- a/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GotopProtocolDecoderTest.java
@@ -2,17 +2,29 @@ package org.traccar.protocol;
import org.junit.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..cb75b4035 100644
--- a/src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gps056FrameDecoderTest.java
@@ -10,7 +10,7 @@ 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..ac3738644 100644
--- a/src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gps056ProtocolDecoderTest.java
@@ -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..cf5786d75 100644
--- a/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java
@@ -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..f6cbe6d17 100644
--- a/src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gps103ProtocolEncoderTest.java
@@ -11,7 +11,7 @@ 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..a1f81b329 100644
--- a/src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GpsGateProtocolDecoderTest.java
@@ -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..bc7910779 100644
--- a/src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GpsMarkerProtocolDecoderTest.java
@@ -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..d1326515f 100644
--- a/src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GpsmtaProtocolDecoderTest.java
@@ -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..a61e708f7 100644
--- a/src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GranitFrameDecoderTest.java
@@ -10,7 +10,7 @@ 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..d2e181e09 100644
--- a/src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/GranitProtocolDecoderTest.java
@@ -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..ce2768448 100644
--- a/src/test/java/org/traccar/protocol/Gs100ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gs100ProtocolDecoderTest.java
@@ -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..25f59a948 100644
--- a/src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gt02ProtocolDecoderTest.java
@@ -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..a9d011277 100644
--- a/src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gt06FrameDecoderTest.java
@@ -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 d2d090c04..23c29b0d3 100644
--- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java
@@ -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"));
@@ -17,6 +17,46 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest {
verifyNull(decoder, binary(
"78780D01086471700328358100093F040D0A"));
+ 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);
+
+ verifyNotNull(decoder, binary(
+ "787831241603060c231e000194620213ee00606a3413ee0060692e000000000000000000000000000000000000000000003a0cb70d0a"));
+
+ verifyNotNull(decoder, binary(
+ "78783B2810010D02020201CC00287D001F713E287D001F7231287D001E232D287D001F4018000000000000000000000000000000000000FF00020005B14B0D0A"));
+
verifyNotNull(decoder, binary(
"78782111150b0b022c30c804b7af7808810cb0003c00012e02d075df0084890c000679950d0a"));
diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java
index 79165d9dc..13463ea39 100644
--- a/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gt06ProtocolEncoderTest.java
@@ -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..48c4306d6 100644
--- a/src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Gt30ProtocolDecoderTest.java
@@ -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..c61c0f0c9 100644
--- a/src/test/java/org/traccar/protocol/H02FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/H02FrameDecoderTest.java
@@ -10,7 +10,7 @@ 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 a0462e675..e68f0814c 100644
--- a/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/H02ProtocolDecoderTest.java
@@ -9,7 +9,13 @@ 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#"));
verifyPosition(decoder, buffer(
"*HQ,4970105243,V1,104000,A,2235.1777,N,11357.8913,E,000.27,235,130721,FFFFFBFF,460,11,d18e105,7752,6#"));
@@ -267,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..1be9421bb 100644
--- a/src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/H02ProtocolEncoderTest.java
@@ -1,5 +1,6 @@
package org.traccar.protocol;
+import org.junit.Before;
import org.junit.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Command;
@@ -14,10 +15,15 @@ import static org.junit.Assert.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());
+ @Before
+ 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..9d26d56c3 100644
--- a/src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HaicomProtocolDecoderTest.java
@@ -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..8fe4d2c8b 100644
--- a/src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HomtecsProtocolDecoderTest.java
@@ -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 35d0f1423..ed7b0534b 100644
--- a/src/test/java/org/traccar/protocol/HoopoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HoopoProtocolDecoderTest.java
@@ -8,11 +8,14 @@ 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\" }"));
+ verifyPosition(decoder, text(
+ "{\"deviceId\":\"BCCD2559\",\"assetName\":\"BCCD2559\",\"assetType\":\"Standard\",\"eventData\":{\"latitude\":32.04746,\"longitude\":34.75843,\"locationName\":\"\",\"accuracyLevel\":\"?????\",\"eventType\":\"InMotion\",\"batteryLevel\":100,\"receiveTime\":\"2022-01-20T08:02:44Z\"},\"address\":{\"line1\":\"????????????70\",\"city\":\"??????-???\",\"stateOrProvince\":\"\",\"postalCode\":\"\",\"countryCode\":\"IL\"},\"movement\":{\"Speed\":1},\"eventTime\":\"2022-01-20T05:55:27Z\",\"serverReportTime\":\"2022-01-20T08:02:48Z\"}"));
+
}
}
diff --git a/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java b/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java
index 228f41ee8..991e0b36d 100644
--- a/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HuaShengFrameDecoderTest.java
@@ -10,7 +10,7 @@ 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..7002d7e88 100644
--- a/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HuaShengProtocolDecoderTest.java
@@ -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"));
diff --git a/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java
index d4789032d..6b902fb46 100644
--- a/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HuabaoFrameDecoderTest.java
@@ -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 bf94c5dc5..e91c84d79 100644
--- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java
@@ -9,11 +9,59 @@ 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"));
+
+ 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");
+
+ verifyPosition(decoder, binary(
+ "7E020000830191715904370A2E00000000800000030158991806CA0FEB00040000010D211108194050010400000003CC14383938363034373831303230373033313836303830011A8001AA810213888202007A8301148401AA8502189B8601338702007D028801338901148A0200998B1131323334353637383941424344454647488C04000200A88D0200828E0114A0002E7E"));
+
+ verifyPosition(decoder, binary(
+ "7e0200007c0191718447540dcd000000008000000b029eabc204ba78510004000000042111182321120104000017f6cc14383933303237323037303339333033383732373130011d800134810204718202008283010e84017b85021ae986012f870201788901038b114a4e31424a314352364b573333363533358c040008dcb68d02018c8e013da000c07e"));
+
verifyNotNull(decoder, binary(
"7e207002940121523001530047210927151009000e002d80ac210927151010000e002d80ab210927151011000e002d80ac210927151012000e002e80ab210927151013000e002d80ab210927151014000e002d80ab210927151015000e002d80ab210927151016000e002d80aa210927151017000e002e80ab210927151018000e002d80ab210927151019000e002e80ac210927151020000e002d80ab210927151021000e002d80ab210927151022000d002d80ac210927151023000e002d80ac210927151024000e002e80ab210927151025000e002e80b0210927151026000e002e80ab210927151027000e002d80ab210927151028000e002e80b0210927151029000e002d80b0210927151030000e002e80ab210927151031000e002d80ab210927151032000e002d80aa210927151033000e002d80ab210927151034000e002d80ab210927151035000e002d80ab210927151036000e002d80ab210927151037000e002d80ab210927151038000e002d80b0210927151039000d002e80aa210927151040000e002d80ab210927151041000e002d80a5210927151042000e002e80ab210927151043000e002d80aa210927151044000e002d80ab210927151045000e002d80ab210927151046000e002d80ac210927151047000e002e80ab210927151048000e002e80a5210927151049000e002d80ab210927151050000e002d80ab210927151051000e002d80ab210927151052000e002d80ab210927151053000e002d80aa210927151054000e002e80b0210927151055000e002e80ab210927151056000e002d80ac210927151057000e002e80ab210927151058000e002d80ab210927151059000e002e80ab210927151100000e002d80ab210927151101000e002e80aa210927151102000e002d80a6210927151103000e002e80a5847e"));
diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java
index 1cb273c2b..6f9c8250a 100644
--- a/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/HuabaoProtocolEncoderTest.java
@@ -11,7 +11,7 @@ public class HuabaoProtocolEncoderTest extends ProtocolTest {
@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..5503ab02c 100644
--- a/src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HunterProProtocolDecoderTest.java
@@ -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..1bd52ce89 100644
--- a/src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/IdplProtocolDecoderTest.java
@@ -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..b6e12aef5 100644
--- a/src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/IntellitracProtocolDecoderTest.java
@@ -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..c668084a1 100644
--- a/src/test/java/org/traccar/protocol/IotmProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/IotmProtocolDecoderTest.java
@@ -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..26f28916c 100644
--- a/src/test/java/org/traccar/protocol/ItsFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ItsFrameDecoderTest.java
@@ -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..dd8d3a0d9 100644
--- a/src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ItsProtocolDecoderTest.java
@@ -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..195fc4258 100644
--- a/src/test/java/org/traccar/protocol/ItsProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/ItsProtocolEncoderTest.java
@@ -11,7 +11,7 @@ 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..b08dff4e7 100644
--- a/src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Ivt401ProtocolDecoderTest.java
@@ -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
new file mode 100644
index 000000000..b275e6d01
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/JidoProtocolDecoderTest.java
@@ -0,0 +1,21 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class JidoProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ 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"));
+
+ verifyPosition(decoder, text(
+ "*12345678910101000,03,130517,160435,1820.5845,N,07833.2478,E,1,58"));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java
index 13137006c..a1b0acac5 100644
--- a/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/JpKorjarProtocolDecoderTest.java
@@ -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..1bc5d8480 100644
--- a/src/test/java/org/traccar/protocol/JsonFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/JsonFrameDecoderTest.java
@@ -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..8e408e50f 100644
--- a/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Jt600FrameDecoderTest.java
@@ -8,7 +8,7 @@ public class Jt600FrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new Jt600FrameDecoder();
+ var decoder = inject(new Jt600FrameDecoder());
verifyFrame(
binary("2480413009781914003406102107544354193631006213423b00000000006c070000000020e064f91ea0671d00020f0f0f0f0f0f0f0f0f0f07f100ea0f6e"),
diff --git a/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java
index 3c681ec58..fc52e32e3 100644
--- a/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Jt600ProtocolDecoderTest.java
@@ -1,15 +1,20 @@
package org.traccar.protocol;
-import org.traccar.ProtocolTest;
-
import org.junit.Test;
+import org.traccar.ProtocolTest;
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)"));
verifyPositions(decoder, binary(
"2480413009781914003406102107544354193631006213423b00000000006c070000000020e064f91ea0671d00020f0f0f0f0f0f0f0f0f0f07f100ea0f6e"));
diff --git a/src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/Jt600ProtocolEncoderTest.java
index 51cefb962..fdd73b9ce 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.traccar.ProtocolTest;
import org.traccar.model.Command;
+import static org.junit.Assert.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..a705d8082 100755
--- a/src/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/KenjiProtocolDecoderTest.java
@@ -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..155493bea 100644
--- a/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/KhdProtocolDecoderTest.java
@@ -8,7 +8,7 @@ public class KhdProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new KhdProtocolDecoder(null);
+ var decoder = inject(new KhdProtocolDecoder(null));
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..468083f35 100644
--- a/src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/KhdProtocolEncoderTest.java
@@ -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..084ae0498 100644
--- a/src/test/java/org/traccar/protocol/L100FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/L100FrameDecoderTest.java
@@ -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..56281cda0 100644
--- a/src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/L100ProtocolDecoderTest.java
@@ -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..45544241f 100644
--- a/src/test/java/org/traccar/protocol/LacakProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/LacakProtocolDecoderTest.java
@@ -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..aacf9abc8 100644
--- a/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/LaipacProtocolDecoderTest.java
@@ -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..ea31bc99d 100644
--- a/src/test/java/org/traccar/protocol/LeafSpyProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/LeafSpyProtocolDecoderTest.java
@@ -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..674738c82 100644
--- a/src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/M2cProtocolDecoderTest.java
@@ -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..0d812ebfc 100644
--- a/src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/M2mProtocolDecoderTest.java
@@ -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..be0fe502e 100644
--- a/src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MaestroProtocolDecoderTest.java
@@ -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..a77043b9d 100644
--- a/src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ManPowerProtocolDecoderTest.java
@@ -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..0c74d4772 100644
--- a/src/test/java/org/traccar/protocol/Mavlink2ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Mavlink2ProtocolDecoderTest.java
@@ -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..854564cd2 100644
--- a/src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MegastekFrameDecoderTest.java
@@ -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..964c59927 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.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..379cf28f9 100644
--- a/src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MeiligaoFrameDecoderTest.java
@@ -11,7 +11,7 @@ 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..4c6eae847 100644
--- a/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MeiligaoProtocolDecoderTest.java
@@ -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..1f2e5f7e3 100644
--- a/src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/MeiligaoProtocolEncoderTest.java
@@ -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..a55935ed2 100644
--- a/src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MeitrackFrameDecoderTest.java
@@ -10,7 +10,7 @@ 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 58861c139..ce0a1e922 100644
--- a/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MeitrackProtocolDecoderTest.java
@@ -9,7 +9,20 @@ public class MeitrackProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new MeitrackProtocolDecoder(null);
+ var decoder = inject(new MeitrackProtocolDecoder(null));
+
+ 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"));
verifyPosition(decoder, buffer(
"$$D149,867047043162018,AAA,35,-1.264865,36.800705,211001105240,A,9,20,41.0,323,1,1697,1,0,000|00||,0000,4.33|12.96|1.92|2.72|2.69,0.000000|0|0.000000,*E1"));
@@ -119,6 +132,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..cc8847db2 100644
--- a/src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/MeitrackProtocolEncoderTest.java
@@ -11,7 +11,7 @@ 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 4c17bf1f8..5e36abe5b 100644
--- a/src/test/java/org/traccar/protocol/MictrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MictrackProtocolDecoderTest.java
@@ -9,7 +9,10 @@ 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"));
verifyAttribute(decoder, text(
"867035041390699 netlock=Success!"),
@@ -45,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..275672554 100644
--- a/src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MilesmateProtocolDecoderTest.java
@@ -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 2d7e4e597..a8f1be855 100644
--- a/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MiniFinderProtocolDecoderTest.java
@@ -2,13 +2,14 @@ package org.traccar.protocol;
import org.junit.Test;
import org.traccar.ProtocolTest;
+import org.traccar.model.Position;
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"));
@@ -19,7 +20,11 @@ public class MiniFinderProtocolDecoderTest extends ProtocolTest {
verifyNull(decoder, text(
"!1,123456789012345"));
- verifyNull(decoder, text(
+ verifyAttribute(decoder, text(
+ "!5,17,V,50"),
+ Position.KEY_BATTERY_LEVEL, 50);
+
+ verifyAttributes(decoder, text(
"!5,17,V"));
verifyNull(decoder, text(
diff --git a/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java
index 652490b72..502f8e8bf 100644
--- a/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/MiniFinderProtocolEncoderTest.java
@@ -11,7 +11,7 @@ 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..0809996f6 100644
--- a/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Minifinder2ProtocolDecoderTest.java
@@ -8,7 +8,14 @@ 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(
+ "ab102600080f1400011001383633393231303339393833343736092429b347633003a96409020000008027b34763"),
+ "bark", true);
+
+ verifyPositions(decoder, binary(
+ "AB103D0035A700000110013836373733303035333430333237390924AC5783620103C250162030CC5F0D5002FB432D00AF005A3158006D0A00000B0931EC5783620A000000"));
verifyPositions(decoder, binary(
"ab10350015ae59010110013836333932313033333836353231360924723a12610042535a182ac0f6b4f2923100c900af02215c2b9bfb5461736b4c4d53"));
diff --git a/src/test/java/org/traccar/protocol/MobilogixProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/MobilogixProtocolDecoderTest.java
index ddfa6ad8b..fea74db7a 100644
--- a/src/test/java/org/traccar/protocol/MobilogixProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MobilogixProtocolDecoderTest.java
@@ -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..82781550e 100644
--- a/src/test/java/org/traccar/protocol/MoovboxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MoovboxProtocolDecoderTest.java
@@ -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..f3ebb8e5c 100644
--- a/src/test/java/org/traccar/protocol/MotorProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MotorProtocolDecoderTest.java
@@ -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..8a5e228c7 100644
--- a/src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MtxProtocolDecoderTest.java
@@ -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..68a68c9e8 100644
--- a/src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/MxtProtocolDecoderTest.java
@@ -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..8eda687cc 100644
--- a/src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NavigilProtocolDecoderTest.java
@@ -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..29327f7e1 100644
--- a/src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NavisFrameDecoderTest.java
@@ -1,8 +1,7 @@
package org.traccar.protocol;
-import org.traccar.ProtocolTest;
-
import org.junit.Test;
+import org.traccar.ProtocolTest;
public class NavisFrameDecoderTest extends ProtocolTest {
diff --git a/src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/NavisProtocolDecoderTest.java
index b1282cac7..960ed1442 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.traccar.ProtocolTest;
-
import org.junit.Test;
+import org.traccar.ProtocolTest;
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..d15d01cc0 100644
--- a/src/test/java/org/traccar/protocol/NavisetFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NavisetFrameDecoderTest.java
@@ -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..d7643b50c 100644
--- a/src/test/java/org/traccar/protocol/NavisetProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NavisetProtocolDecoderTest.java
@@ -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 07b19651b..360f92447 100644
--- a/src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NavtelecomFrameDecoderTest.java
@@ -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"),
@@ -19,13 +19,16 @@ public class NavtelecomFrameDecoderTest extends ProtocolTest {
binary("404e544301000000000000002a005e6c2a3e464c4558b01e1efffffe300a08080ffffe08000000580028002bc0000000000000b4000000000000"),
decoder.decode(null, null, binary("404e544301000000000000002a005e6c2a3e464c4558b01e1efffffe300a08080ffffe08000000580028002bc0000000000000b4000000000000")));
+ verifyNull(
+ decoder.decode(null, null, binary("7f")));
+
}
@Ignore
@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..301a72b2a 100644
--- a/src/test/java/org/traccar/protocol/NavtelecomProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NavtelecomProtocolDecoderTest.java
@@ -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..c63c19a29
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/NdtpV6ProtocolDecoderTest.java
@@ -0,0 +1,18 @@
+package org.traccar.protocol;
+
+import org.junit.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..4e9e55f62 100644
--- a/src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NeosProtocolDecoderTest.java
@@ -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..239d892f8 100644
--- a/src/test/java/org/traccar/protocol/NetProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NetProtocolDecoderTest.java
@@ -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..03aaa49aa 100644
--- a/src/test/java/org/traccar/protocol/NiotProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NiotProtocolDecoderTest.java
@@ -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..3f1ec7aee 100644
--- a/src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NoranProtocolDecoderTest.java
@@ -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..d1b28525c 100644
--- a/src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/NoranProtocolEncoderTest.java
@@ -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..dd5e1d9b9 100644
--- a/src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NvsFrameDecoderTest.java
@@ -10,7 +10,7 @@ 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..61d050679 100644
--- a/src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NvsProtocolDecoderTest.java
@@ -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..b3bd9aca7 100644
--- a/src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/NyitechProtocolDecoderTest.java
@@ -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..8272fe41e 100644
--- a/src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ObdDongleProtocolDecoderTest.java
@@ -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..6015f1d18 100644
--- a/src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OigoProtocolDecoderTest.java
@@ -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..19c96ed9a 100644
--- a/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OkoProtocolDecoderTest.java
@@ -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..8e8d9b1cf 100644
--- a/src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OmnicommFrameDecoderTest.java
@@ -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..5b3b08194 100644
--- a/src/test/java/org/traccar/protocol/OmnicommProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OmnicommProtocolDecoderTest.java
@@ -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..5494301d8 100644
--- a/src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OpenGtsProtocolDecoderTest.java
@@ -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
new file mode 100644
index 000000000..408053496
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java
@@ -0,0 +1,24 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class OrbcommProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new OrbcommProtocolDecoder(null));
+
+ verifyNull(decoder, response(
+ buffer("{\"ErrorID\":0,\"NextStartUTC\":\"\",\"Messages\":null}")));
+
+ verifyPositions(decoder, response(
+ buffer("{\"ErrorID\":0,\"NextStartUTC\":\"2022-02-17 08:44:45\",\"Messages\":[{\"ID\":10343663424,\"MessageUTC\":\"2022-02-17 08:44:45\",\"ReceiveUTC\":\"2022-02-17 08:44:45\",\"SIN\":126,\"MobileID\":\"01452955SKYB444\",\"Payload\":{\"Name\":\"MovingIntervalSat\",\"SIN\":126,\"MIN\":22,\"Fields\":[{\"Name\":\"Latitude\",\"Value\":\"727668\"},{\"Name\":\"Longitude\",\"Value\":\"902276\"},{\"Name\":\"Speed\",\"Value\":\"0\"},{\"Name\":\"Heading\",\"Value\":\"361\"},{\"Name\":\"EventTime\",\"Value\":\"1645087473\"}]},\"RegionName\":\"EMEARB6\",\"OTAMessageSize\":16,\"CustomerID\":0,\"Transport\":1,\"MobileOwnerID\":60003097}]}")));
+
+ verifyPositions(decoder, false, response(
+ buffer("{\"ErrorID\":0,\"NextStartUTC\":\"2016-10-13 15:19:59\",\"Messages\":[{\"ID\":120213064,\"MessageUTC\":\"2016-10-12 12:42:01\",\"ReceiveUTC\":\"2016-10-12 12:42:01\",\"SIN\":0,\"MobileID\":\"01173096SKY0E45\",\"Payload\":{\"Name\":\"modemRegistration\",\"SIN\":0,\"MIN\":0,\"Fields\":[{\"Name\":\"hardwareMajorVersion\",\"Value\":\"4\"},{\"Name\":\"hardwareMinorVersion\",\"Value\":\"2\"},{\"Name\":\"softwareMajorVersion\",\"Value\":\"13\"},{\"Name\":\"softwareMinorVersion\",\"Value\":\"1\"},{\"Name\":\"product\",\"Value\":\"4\"},{\"Name\":\"wakeupPeriod\",\"Value\":\"None\"},{\"Name\":\"lastResetReason\",\"Value\":\"Software\"},{\"Name\":\"virtualCarrier\",\"Value\":\"6\"},{\"Name\":\"beam\",\"Value\":\"1\"},{\"Name\":\"vain\",\"Value\":\"0\"},{\"Name\":\"reserved\",\"Value\":\"0\"},{\"Name\":\"operatorTxState\",\"Value\":\"0\"},{\"Name\":\"userTxState\",\"Value\":\"0\"},{\"Name\":\"broadcastIDCount\",\"Value\":\"0\"}],\"RegionName\":\"AMERRB11\",\"OTAMessageSize\":15,\"CustomerID\":0}}]}")));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java
index 7368a9d4e..f5b98574c 100644
--- a/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OrionProtocolDecoderTest.java
@@ -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..3b8a94613 100644
--- a/src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OsmAndProtocolDecoderTest.java
@@ -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..edb7d1aad 100644
--- a/src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OutsafeProtocolDecoderTest.java
@@ -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..03332e7fe 100644
--- a/src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/OwnTracksProtocolDecoderTest.java
@@ -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..bde464162 100644
--- a/src/test/java/org/traccar/protocol/PacificTrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PacificTrackProtocolDecoderTest.java
@@ -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..97020343f 100644
--- a/src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PathAwayProtocolDecoderTest.java
@@ -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..0dd00462d 100644
--- a/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java
@@ -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..8b15d70a6 100644
--- a/src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PluginProtocolDecoderTest.java
@@ -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..8bf109d11 100644
--- a/src/test/java/org/traccar/protocol/PolteProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PolteProtocolDecoderTest.java
@@ -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..8bc16d373 100644
--- a/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PortmanProtocolDecoderTest.java
@@ -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..b4c334a0c 100644
--- a/src/test/java/org/traccar/protocol/PortmanProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/PortmanProtocolEncoderTest.java
@@ -9,9 +9,9 @@ import static org.junit.Assert.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..5dbde7846 100644
--- a/src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PretraceProtocolDecoderTest.java
@@ -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..d3218d4a8 100644
--- a/src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/PretraceProtocolEncoderTest.java
@@ -11,7 +11,7 @@ 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..8c2081641 100644
--- a/src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PricolProtocolDecoderTest.java
@@ -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..9129a3079 100644
--- a/src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ProgressProtocolDecoderTest.java
@@ -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..172d85df6 100644
--- a/src/test/java/org/traccar/protocol/PstFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PstFrameDecoderTest.java
@@ -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/PstProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PstProtocolDecoderTest.java
index 445c333c1..880caf727 100644
--- a/src/test/java/org/traccar/protocol/PstProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/PstProtocolDecoderTest.java
@@ -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..6c3ff71b6 100644
--- a/src/test/java/org/traccar/protocol/PstProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/PstProtocolEncoderTest.java
@@ -7,9 +7,9 @@ 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..a5f5d7e77 100644
--- a/src/test/java/org/traccar/protocol/Pt215ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Pt215ProtocolDecoderTest.java
@@ -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..f7b278139 100644
--- a/src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Pt3000ProtocolDecoderTest.java
@@ -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..854c789b8 100644
--- a/src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Pt502FrameDecoderTest.java
@@ -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..f310b2227 100644
--- a/src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Pt502ProtocolDecoderTest.java
@@ -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..c97093e26 100644
--- a/src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/Pt502ProtocolEncoderTest.java
@@ -11,7 +11,7 @@ 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..b198ac28e 100644
--- a/src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Pt60ProtocolDecoderTest.java
@@ -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..a363022f0 100644
--- a/src/test/java/org/traccar/protocol/R12wProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/R12wProtocolDecoderTest.java
@@ -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..ff40c19a3 100644
--- a/src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RaceDynamicsProtocolDecoderTest.java
@@ -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..b5a2555b1 100644
--- a/src/test/java/org/traccar/protocol/RadarProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RadarProtocolDecoderTest.java
@@ -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..3da671dbf 100644
--- a/src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RaveonProtocolDecoderTest.java
@@ -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..5bdfd6816 100644
--- a/src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RecodaProtocolDecoderTest.java
@@ -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..eb591a5f6 100644
--- a/src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RetranslatorProtocolDecoderTest.java
@@ -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..df19f01c6
--- /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.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..0d7eeb0df 100644
--- a/src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RitiProtocolDecoderTest.java
@@ -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..e4b30538c 100644
--- a/src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RoboTrackFrameDecoderTest.java
@@ -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..db1617c9e 100644
--- a/src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RoboTrackProtocolDecoderTest.java
@@ -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..b301507fb 100644
--- a/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RstProtocolDecoderTest.java
@@ -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..89d4a02cc 100644
--- a/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/RuptelaProtocolDecoderTest.java
@@ -8,7 +8,10 @@ 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, binary(
"00800003167d765c155d01000160cd0a310000faae43f7176ee45702332b0c12000006070d05007300cfff260082008600870088000f00d7021100d801c900061d0000c500001e0e988300008900008b000002d0000c9bca720c889a0b047e00000000000000007f0000000000000000800000000000000000810000000000000000a341"));
diff --git a/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java b/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java
index 409cd4da5..0c4fc6767 100644
--- a/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/RuptelaProtocolEncoderTest.java
@@ -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 d4918e121..2b7f40c82 100644
--- a/src/test/java/org/traccar/protocol/S168ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/S168ProtocolDecoderTest.java
@@ -8,7 +8,16 @@ 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"));
+
+ verifyPosition(decoder, text(
+ "S168#861118010104168#0715#0124#LOCA:W;CELL:6,1cc,0,5847,2c54cc1,1d,5847,cc98145,1b,5847,6259d03,e,5847,cc98141,1d,5847,6259e03,27,5847,32113ce,28;GDATA:V,0,220205152238,0.0,0.0,0,0,0;ALERT:0000;STATUS:99,52;WIFI:5,8C-AB-8E-9D-73-18,-56,60-3A-7C-E2-D3-85,-72,62-3A-7C-A2-D3-85,-72,00-00-00-00-00-00,-75,50-70-97-B1-80-1F,-82"));
+
+ verifyPosition(decoder, text(
+ "S168#358511039001705#003a#01ca#LOCA:G;CELL:6,1cc,0,2479,de11150,2e,2479,d6e4546,31,2479,d6e4547,39,778c,787cc30,39,778c,787cc31,40,253f,6195502,32;GDATA:A,5,220117220950,22.779583,113.820633,5,296,35;ALERT:0080;STATUS:98,73;;FARM:0,0009,0000,010a,20220117220950;WIFI:10,CC-08-FB-A5-49-B3,-28,08-40-F3-7F-6C-A9,-59,A4-29-40-65-2C-42,-74,80-89-17-A5-6F-7B,-82,80-EA-07-82-93-C6,-82,FC-37-2B-34-D6-A1,-83,34-6B-5B-A9-49-15,-83,BC-46-99-B3-51-10,-84,BC-54-FC-53-0A-D1,-84,3C-CD-57-67-D1-32,-85"));
verifyNull(decoder, text(
"S168#358511139046180#00c9#0009#SYNC:0000"));
diff --git a/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java b/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java
index ced40acd0..15b1d0451 100644
--- a/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SabertekFrameDecoderTest.java
@@ -10,7 +10,7 @@ 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..6aafa325f 100644
--- a/src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SabertekProtocolDecoderTest.java
@@ -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..d0ae6fabf 100644
--- a/src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SanavProtocolDecoderTest.java
@@ -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..57398dd84 100644
--- a/src/test/java/org/traccar/protocol/SanulProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SanulProtocolDecoderTest.java
@@ -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..0fe16377d 100644
--- a/src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SatsolProtocolDecoderTest.java
@@ -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..66d5f5e69 100644
--- a/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SigfoxProtocolDecoderTest.java
@@ -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..0d7eb4f16 100644
--- a/src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SiwiProtocolDecoderTest.java
@@ -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..e59e3c3f0 100644
--- a/src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SkypatrolProtocolDecoderTest.java
@@ -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..258eb0fce 100644
--- a/src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SmartSoleProtocolDecoderTest.java
@@ -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..de025c18e 100644
--- a/src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SmokeyProtocolDecoderTest.java
@@ -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..445628f6d 100644
--- a/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SolarPoweredProtocolDecoderTest.java
@@ -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..03d0e97f0 100644
--- a/src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SpotProtocolDecoderTest.java
@@ -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..0a6ad0163 100644
--- a/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/StarLinkProtocolDecoderTest.java
@@ -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..84c470970 100644
--- a/src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/StarcomProtocolDecoderTest.java
@@ -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 5d22344fa..072c19942 100644
--- a/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/StartekProtocolDecoderTest.java
@@ -9,7 +9,15 @@ public class StartekProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new StartekProtocolDecoder(null);
+ var decoder = inject(new StartekProtocolDecoder(null));
+
+ 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..f04d0cb67 100644
--- a/src/test/java/org/traccar/protocol/StartekProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/StartekProtocolEncoderTest.java
@@ -9,9 +9,9 @@ import static org.junit.Assert.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..c618ac21c 100644
--- a/src/test/java/org/traccar/protocol/StbProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/StbProtocolDecoderTest.java
@@ -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..3ef4b1901 100644
--- a/src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Stl060ProtocolDecoderTest.java
@@ -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..6d0351a8e 100644
--- a/src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SuntechFrameDecoderTest.java
@@ -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 a9720f437..107c03d36 100644
--- a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java
@@ -1,5 +1,6 @@
package org.traccar.protocol;
+import org.junit.Ignore;
import org.junit.Test;
import org.traccar.ProtocolTest;
import org.traccar.model.Position;
@@ -7,80 +8,20 @@ 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);
-
- 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);
+ public void testDecode() throws Exception {
- 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;:"));
+ var decoder = inject(new SuntechProtocolDecoder(null));
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);
-
- 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");
+ "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;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"));
@@ -91,6 +32,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");
@@ -257,4 +209,87 @@ public class SuntechProtocolDecoderTest extends ProtocolTest {
}
+ @Ignore
+ @Test
+ public void testDecodeCrash() throws Exception {
+
+ var decoder = inject(new SuntechProtocolDecoder(null));
+
+ verifyAttribute(decoder, binary(
+ "4352523b303931303030303036333b313b313b303135303b16011c150f0ad82f6c0000000000ae037085fbff7700fd00faff6300f30000006800fb000d007100fa00f32f6c00000000005e044a80fcff6f000301e1ff5d00e900e1ff6400e600f4ff5b00ec000a306c00000000002104248306006c000501fcff5b00e00001006e000101eeff4e00e10022306c00000000005c041a7e00006a00010100005d00f800b5ff7cffdf0050009300fc003b44350d"),
+ Position.KEY_G_SENSOR, "");
+
+ }
+
+ @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..e96c9b62d 100755
--- a/src/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SupermateProtocolDecoderTest.java
@@ -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..fb9053706 100644
--- a/src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SviasProtocolDecoderTest.java
@@ -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..923b7abfb 100644
--- a/src/test/java/org/traccar/protocol/SwiftechProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/SwiftechProtocolDecoderTest.java
@@ -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..1622f64f2 100644
--- a/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/T55ProtocolDecoderTest.java
@@ -9,7 +9,10 @@ public class T55ProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new T55ProtocolDecoder(null);
+ var decoder = inject(new T55ProtocolDecoder(null));
+
+ 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 +124,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..40d5bc9e9 100644
--- a/src/test/java/org/traccar/protocol/T57FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/T57FrameDecoderTest.java
@@ -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..2e097562b 100644
--- a/src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/T57ProtocolDecoderTest.java
@@ -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/T800xProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java
index 1dd4e8619..10d0aad59 100644
--- a/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/T800xProtocolDecoderTest.java
@@ -9,7 +9,10 @@ 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(
+ "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..b2d7c57a2 100644
--- a/src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/T800xProtocolEncoderTest.java
@@ -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..36c9d9148 100644
--- a/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TaipProtocolDecoderTest.java
@@ -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..b4617cb61 100644
--- a/src/test/java/org/traccar/protocol/TechTltProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TechTltProtocolDecoderTest.java
@@ -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
new file mode 100644
index 000000000..36c3b578b
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/TechtoCruzFrameDecoderTest.java
@@ -0,0 +1,25 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+import static org.junit.Assert.assertEquals;
+
+public class TechtoCruzFrameDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ var decoder = inject(new TechtoCruzFrameDecoder());
+
+ assertEquals(
+ buffer("$$A35,RESPO|G33|8612345678910|CRUZ,*E3"),
+ decoder.decode(null, null, buffer("$$A35,RESPO|G33|8612345678910|CRUZ,*E3")));
+
+ assertEquals(
+ buffer("$$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"),
+ decoder.decode(null, null, buffer("$$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/TechtoCruzProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TechtoCruzProtocolDecoderTest.java
index 8f4a7915d..459401469 100644
--- a/src/test/java/org/traccar/protocol/TechtoCruzProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TechtoCruzProtocolDecoderTest.java
@@ -8,11 +8,14 @@ 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"));
+ verifyNull(decoder, text(
+ "$$A35,RESPO|G33|8612345678910|CRUZ,*E3"));
+
}
}
diff --git a/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java b/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java
index f315e6432..98b2b80c4 100644
--- a/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TekFrameDecoderTest.java
@@ -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..17910a8d6 100644
--- a/src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TekProtocolDecoderTest.java
@@ -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..9f36b3f96 100644
--- a/src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TelemaxProtocolDecoderTest.java
@@ -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..dc6cc58c6 100644
--- a/src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TelicFrameDecoderTest.java
@@ -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..214bb06c7 100644
--- a/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TelicProtocolDecoderTest.java
@@ -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..adc768460 100644
--- a/src/test/java/org/traccar/protocol/TeltonikaFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TeltonikaFrameDecoderTest.java
@@ -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 082d410c2..ba64642f2 100644
--- a/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TeltonikaProtocolDecoderTest.java
@@ -9,12 +9,27 @@ 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"));
verifyPositions(decoder, binary(
+ "00000000000000a28e0100000183ac617e3001123eb99b1e142db4000000000000000000001d000900f000005000001503004500011e1801212d01242a012722012a18001100b5000000b600000018000000cd151000431c2d011f6981012047d701226981012347d901256981012647d8012869810129e6f304b0000304b1000304b2000304b30003000100f10000639d0002000b0000000214bf12fe000e0000000029d18c95000001000051b6"));
+
+ verifyPositions(decoder, binary(
+ "00000000000004258e0400000182a701b49301d5d90ab7ebe4aae101be003d12000000f7003d000e00f70100ef0000f00000500500150200c800004501000100001d00001400001600001700007157010701001d00b5000b00b60006004230400018000000cd223f00ce741700430f8900440000000d00010011ffe50012001f0013ffce000f03e800190bb8001a0bb8001b0bb8001c0bb800560bb800680bb8006a0bb8006c0bb8010e0000011100000114000001170000014f0000015000000151000001520000000a00f100011d2a00c700000000001000b9addc000c0000acb600040000000001320000000001330000000001340000000001350000000001c1000000000003000b000000d14675f36000ee0000000000000000000e0000000003fd509f0005014b0000014c0000014d0000014e0000018300222d3333373333382e0100000053a6fb624588040001ba86064f0eae51c0fdaf4d3de500000182a701b82001d5d90ab7ebe4aae101be003d12000000f0003c000d00ef0000f00100500500150200c800004501000100001d00001400001600001700007152010701001d00b5000900b60006004217e50018000000cd223f00ce741700430f5c00440000000d00010011fed60012fd1d0013f1f2000f03e800190bb8001a0bb8001b0bb8001c0bb800560bb800680bb8006a0bb8006c0bb8010e0000011100000114000001170000014f0000015000000151000001520000000a00f100011d2a00c700000000001000b9addc000c0000acb600040000000001320000000001330000000001340000000001350000000001c1000000000003000b000000d14675f36000ee0000000000000000000e0000000003fd509f0005014b0000014c0000014d0000014e0000018300222d3333373333352e353833332d303730373139362e323333332b3030302e3434362f00000182a701bc0801d5d90ab7ebe4aae101be003d12000000fc003d000e00ef0000f00100500500150200c800004501000100001d0000140000160000170000714d01070100fc01001d00b5000900b60006004217e50018000000cd223f00ce741700430f5c00440000000d00010011fed60012fd1d0013f1f2000f03e800190bb8001a0bb8001b0bb8001c0bb800560bb800680bb8006a0bb8006c0bb8010e0000011100000114000001170000014f0000015000000151000001520000000a00f100011d2a00c700000000001000b9addc000c0000acb600040000000001320000000001330000000001340000000001350000000001c1000000000003000b000000d14675f36000ee0000000000000000000e0000000003fd509f0005014b0000014c0000014d0000014e0000018300222d3333373333352e353833332d303730373139362e323333332b3030302e3434362f00000182a7018d8d01d5d8ffa6ebe4a0ca01be006111000000f70001000100f70500000000000000000400003a10"));
+
+ verifyPositions(decoder, binary(
+ "00000000000003831004000001735ace37f80000e3b9331c71e290006900e211005100fd072e1600010100160300470300f00100150400b20000c80000ef01009000004f00005101005201005300005538006e00006f00007a03007d00007f5600890000fd0200fe1f09004326b00044000000b5000b00b6000600427029001800540046015d00ce4ec10080000f0f00f10000515400cd007404ab00d80f5022a1005000000054005400000000005600015568005700000060005800000420006800001113006d303330300071fffd8c85008700000020008800000002008a000155f5008b0000b86000000001735ace3ca80000e3b08a1c71dd29006900e311005100fd072e1600010100160300470300f00100150400b20000c80000ef01009000004f00005101005201005300005537006e00006f00007a03007d00007f5600890000fd0200fe1d09004326ac0044000000b5000b00b600060042701f001800540046015d00ce4ec10080000f0f00f10000515400cd007404ab00d80f5022ce00500000005400540000000000560001556800570000006000580000041f006800001113006d303330300071fffd8c85008700000020008800000002008a000155f5008b0000b86000000001735ace3fc80000e3a7c01c71d7c2006900e311005100fd072e1600010100160300470300f00100150400b20000c80000ef01009000004f00005101005201005300005537006e00006f00007a03007d00007f5600890000fd0200fe2309004326ac0044000000b5000b00b6000600427015001800540046015e00ce4ec10080000f0f00f10000515400cd007404ab00d80f5022e700500000005400540000000000560001556800570000006000580000041f006800001113006d303330300071fffd8c85008700000020008800000002008a000155f5008b0000b86000000001735ace3ffa0000e3a7c01c71d7c2006900e311005100fd072e1600010100160300470300f00100150400b20000c80000ef01009000004f00005101005201005300005537006e00006f00007a03007d00007f5600890000fd0300fe2309004326ac0044000000b5000b00b6000600427015001800540046015e00ce4ec10080000f0f00f10000515400cd007404ab00d80f5022e700500000005400540000000000560001556800570000006000580000041f006800001113006d303330300071fffd8c85008700000020008800000002008a000155f5008b0000b86000040000eb85"));
+
+ verifyPositions(decoder, binary(
+ "00000000000000e708030000018293d62060000de1f6a62159767e00000000000000000b074504f00050041500c801ef004f630342320043000344000001f100006019000000018291b0c790000de1f6a62159767e006e0144070000ef12074503f00050051505c800ef004f0207b5000eb6000b423324180000ce00dc43001144000004c700000007f100006019cd0003c7776300ea4e2e000000018291aff0b8000de1f91f21597405006f00f61300080012074503f00150051504c800ef014f0207b50009b600054236c1180008ce00dc43003f44000004c700000003f100006019cd0003c7776300ea4e2700030000a48d"));
+
+ verifyPositions(decoder, binary(
+ "00000000000000da08030000017fcedf499600280431be0eded45d0038012d100000fa100901000200b300b4004501500415034702fa00054232a1180000cd3b2fce281d43001f02c700000006f10000a029000000017fcedea99600280432070eded3dd00380046130009000f0801010200b300b400450150051502470205423276180009cd3b2fce281d43001f02c700000027f10000a0290000000179d50853180027f65d3f0ed67212001500f1110061000f0801010200b300b4004501500515034702054234f4180061cd53d1ce28c043003e02c700000147f1000000290003000052cb"));
+
+ verifyPositions(decoder, binary(
"00000000000000b98e0200000179555c7bf8010b3a1cfbebc142b00000000000000000ec000f000900f00000150000c80000450200710100740001070100fa0000ec01000500b500000018000000430d560044000000190000000100f1000000000000000000000179555c83c8010b3a1cfbebc142b0000000000000000185000f000900f00000150000c80000450200710100740001070100fa00018511000500b500000018000000430d560044000000190000000100f100000000000000000200003251"));
verifyPositions(decoder, binary(
@@ -110,6 +125,9 @@ public class TeltonikaProtocolDecoderTest extends ProtocolTest {
verifyPositions(decoder, binary(
"000000000000004a08010000015ebc1da508002411926621f15246010b00b913005e000f06ef01f00150011505c800450108b5000bb6000642381b18005ecd0318ce19cd430f5844000001f1000061a900010000c8e1"));
+ verifyNull(decoder, binary(
+ "ff"));
+
decoder.setExtended(true);
verifyPositions(decoder, false, binary(
@@ -124,7 +142,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"));
@@ -144,7 +162,7 @@ public class TeltonikaProtocolDecoderTest extends ProtocolTest {
@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..d7e1149aa 100644
--- a/src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/TeltonikaProtocolEncoderTest.java
@@ -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
new file mode 100644
index 000000000..fc66f53bb
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/TeraTrackProtocolDecoderTest.java
@@ -0,0 +1,21 @@
+package org.traccar.protocol;
+
+import org.junit.Test;
+import org.traccar.ProtocolTest;
+
+public class TeraTrackProtocolDecoderTest extends ProtocolTest {
+
+ @Test
+ public void testDecode() throws Exception {
+
+ 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\":[]}"));
+
+ verifyAttributes(decoder, text(
+ "{\"MDeviceID\":\"074054558620\",\"DeviceType\":\"1\",\"DataType\":\"2\",\"DataLength\":\"0913\",\"DateTime\":\"2022-02-22 23:35:35\",\"Latitude\":\"-6.826699\",\"Longitude\":\"39.279008\",\"LatitudeState\":\"0\",\"LongitudeState\":\"1\",\"Speed\":\"0\",\"Mileage\":\"0\",\"FenceAlarm\":\"0\",\"AreaAlarmID\":\"0\",\"LockCutOff\":\"0\",\"SealTempered\":\"1\",\"MessageAck\":\"1\",\"LockRope\":\"0\",\"LockStatus\":\"0\",\"LockOpen\":\"1\",\"PasswordError\":\"0\",\"CardNo\":\"60060198\",\"IllegalCard\":\"0\",\"LowPower\":\"0\",\"UnCoverBack\":\"1\",\"CoverStatus\":\"0\",\"LockStuck\":\"1\",\"Power\":\"90\",\"GSM\":\"14\",\"IMEI\":\"861774054558620\",\"Index\":\"39\",\"Slave\":[{\"SDeviceId\":\"685304\",\"SPower\":\"00\",\"SLockCutOff\":\"0\",\"SLockOpen\":\"1\",\"SUnCoverBack\":\"0\",\"SCoverStatus\":\"1\",\"STimeOut\":\"1\",\"SLockRope\":\"0\",\"SSealTempered\":\"0\",\"SLockStuck\":\"0\"},{\"SDeviceId\":\"224779\",\"SPower\":\"00\",\"SLockCutOff\":\"0\",\"SLockOpen\":\"1\",\"SUnCoverBack\":\"0\",\"SCoverStatus\":\"1\",\"STimeOut\":\"1\",\"SLockRope\":\"0\",\"SSealTempered\":\"0\",\"SLockStuck\":\"0\"}]}"));
+
+ }
+
+}
diff --git a/src/test/java/org/traccar/protocol/ThinkPowerProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/ThinkPowerProtocolDecoderTest.java
index ff808e667..2085112ec 100644
--- a/src/test/java/org/traccar/protocol/ThinkPowerProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ThinkPowerProtocolDecoderTest.java
@@ -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..859dd4f89 100644
--- a/src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/ThinkRaceProtocolDecoderTest.java
@@ -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..90431fa24
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/ThurayaProtocolDecoderTest.java
@@ -0,0 +1,24 @@
+package org.traccar.protocol;
+
+import org.junit.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..3bcc9994a 100644
--- a/src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tk102ProtocolDecoderTest.java
@@ -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..87c3d9317 100644
--- a/src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tk103FrameDecoderTest.java
@@ -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..8b3177136 100644
--- a/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java
@@ -9,7 +9,13 @@ 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(
+ "(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..359e432c7 100644
--- a/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tk103ProtocolEncoderTest.java
@@ -9,9 +9,9 @@ import static org.junit.Assert.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..a6a9f836e 100644
--- a/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tlt2hProtocolDecoderTest.java
@@ -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..d6d1b7275 100644
--- a/src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TlvProtocolDecoderTest.java
@@ -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..9cdcb6169 100644
--- a/src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TmgFrameDecoderTest.java
@@ -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..6d3c36005 100644
--- a/src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TmgProtocolDecoderTest.java
@@ -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..b49345a42 100644
--- a/src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TopflytechProtocolDecoderTest.java
@@ -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 331be974c..5e7ec1136 100644
--- a/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TopinProtocolDecoderTest.java
@@ -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"));
@@ -18,6 +18,10 @@ public class TopinProtocolDecoderTest extends ProtocolTest {
"78780d0103593390754169634d0d0a"));
verifyAttribute(decoder, binary(
+ "7878006921120412565802010601071e4a9764071e4a9864010d0a"),
+ Position.KEY_ALARM, Position.ALARM_VIBRATION);
+
+ verifyAttribute(decoder, binary(
"787801940D0A"),
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..a69f389ac 100644
--- a/src/test/java/org/traccar/protocol/TopinProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/TopinProtocolEncoderTest.java
@@ -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..175c32848 100644
--- a/src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TotemFrameDecoderTest.java
@@ -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..df5734568 100644
--- a/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TotemProtocolDecoderTest.java
@@ -8,7 +8,10 @@ public class TotemProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TotemProtocolDecoder(null);
+ var decoder = inject(new TotemProtocolDecoder(null));
+
+ 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 51e5bac92..97a044b51 100644
--- a/src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/TotemProtocolEncoderTest.java
@@ -11,14 +11,28 @@ 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);
- command.setType(Command.TYPE_ENGINE_STOP);
+ command.setType(Command.TYPE_REBOOT_DEVICE);
command.set(Command.KEY_DEVICE_PASSWORD, "000000");
- assertEquals("*000000,025,C,1#", encoder.encodeCommand(command));
+ assertEquals("$$0020CF000000,0061D", encoder.encodeCommand(command));
+
+ }
+
+ @Test
+ public void testSmsEncode() throws Exception {
+
+ var encoder = inject(new TotemProtocolSmsEncoder(null));
+
+ Command command = new Command();
+ command.setDeviceId(2);
+ command.setType(Command.TYPE_REBOOT_DEVICE);
+ command.set(Command.KEY_DEVICE_PASSWORD, "000000");
+
+ assertEquals("*000000,006#", encoder.encodeCommand(command));
}
diff --git a/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java
index def280b04..e4917c872 100644
--- a/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tr20ProtocolDecoderTest.java
@@ -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..96ddf4175 100644
--- a/src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tr900ProtocolDecoderTest.java
@@ -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..10603db1c 100644
--- a/src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TrackboxProtocolDecoderTest.java
@@ -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..7542b3456 100644
--- a/src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TrakMateProtocolDecoderTest.java
@@ -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..a093d94e9 100644
--- a/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TramigoFrameDecoderTest.java
@@ -8,7 +8,7 @@ public class TramigoFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TramigoFrameDecoder();
+ var decoder = inject(new TramigoFrameDecoder());
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..c2d13d199 100644
--- a/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TramigoProtocolDecoderTest.java
@@ -8,7 +8,7 @@ public class TramigoProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TramigoProtocolDecoder(null);
+ var decoder = inject(new TramigoProtocolDecoder(null));
verifyAttributes(decoder, binary(
"8000c426b000a6000101c557037598050d5c8a595472616d69676f3a204d6f76696e672c20302e3132206b6d2045206f66204c617275742054696e2049736c616d6963205072696d617279205363686f6f6c2c2054616970696e672c20506572616b2c204d592c20342e38333134392c203130302e37333038352c204e572077697468207370656564203130206b6d2f682c2030303a34393a30382041756720392020454f46"));
diff --git a/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java
index 44735abcb..6dc28d89e 100644
--- a/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java
@@ -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"));
@@ -65,6 +65,9 @@ public class TrvProtocolDecoderTest extends ProtocolTest {
verifyPosition(decoder, text(
"TRVAP10080524A2232.9806N11404.9355E000.1061830323.8706000908000502,460,0,9520,3671,00,zh-cn,00"));
+ verifyPosition(decoder, text(
+ "TRVYP14220217A5235.7885N00724.1840E000.0130919177.561000050660000200004,262,01,14635,52789,FritzBox7|DC-39-8F-7E-94-73|-89&FritzBox7|24-4E-5D-71-C3-9C|-90&MY_IOT|80-B4-F7-77-9C-7C|-81&MYAP|44-D4-F7-77-9C-7C|-80#"));
+
}
}
diff --git a/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java
index 5d0e86a3f..3f5c60daa 100644
--- a/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Tt8850ProtocolDecoderTest.java
@@ -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..de6f3a6ff 100644
--- a/src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TytanProtocolDecoderTest.java
@@ -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..4a861fb06 100644
--- a/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/TzoneProtocolDecoderTest.java
@@ -8,7 +8,10 @@ public class TzoneProtocolDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new TzoneProtocolDecoder(null);
+ var decoder = inject(new TzoneProtocolDecoder(null));
+
+ 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..534287e0a 100644
--- a/src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/UlbotechFrameDecoderTest.java
@@ -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..52f2520cc 100644
--- a/src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/UlbotechProtocolDecoderTest.java
@@ -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..50e9321ce 100644
--- a/src/test/java/org/traccar/protocol/UlbotechProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/UlbotechProtocolEncoderTest.java
@@ -7,9 +7,9 @@ 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..8d32eebb1 100644
--- a/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/UproProtocolDecoderTest.java
@@ -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..40776278d 100644
--- a/src/test/java/org/traccar/protocol/UuxProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/UuxProtocolDecoderTest.java
@@ -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..105dc8339 100644
--- a/src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/V680ProtocolDecoderTest.java
@@ -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..042b66cae 100644
--- a/src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/VisiontekProtocolDecoderTest.java
@@ -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/VnetProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/VnetProtocolDecoderTest.java
index d43176a45..25cc03781 100644
--- a/src/test/java/org/traccar/protocol/VnetProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/VnetProtocolDecoderTest.java
@@ -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..7d039dc8f 100644
--- a/src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Vt200FrameDecoderTest.java
@@ -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..25ce5550a 100644
--- a/src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Vt200ProtocolDecoderTest.java
@@ -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..e381153a2 100644
--- a/src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/VtfmsFrameDecoderTest.java
@@ -10,7 +10,7 @@ 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..4925d9769 100644
--- a/src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/VtfmsProtocolDecoderTest.java
@@ -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..42464c6fe 100644
--- a/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WatchFrameDecoderTest.java
@@ -8,7 +8,7 @@ public class WatchFrameDecoderTest extends ProtocolTest {
@Test
public void testDecode() throws Exception {
- var decoder = new WatchFrameDecoder();
+ var decoder = inject(new WatchFrameDecoder());
verifyFrame(
binary("5b33472a3335323636313039303134333135302a303030412a4c4b2c302c302c3130305d"),
diff --git a/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java
index 98e83f491..7eb167a74 100644
--- a/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java
@@ -1,25 +1,36 @@
package org.traccar.protocol;
-import io.netty.buffer.ByteBuf;
import org.junit.Test;
-import org.traccar.Context;
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));
+
+ 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]"),
Position.PREFIX_TEMP + 1, 35.29);
verifyPosition(decoder, buffer(
+ "[SG*9159059735*0066*UD2,230322,082138,A,59.55285,N,016.66185,E,0.0,000,26,14,80,70,0,50,00000000,1,1,240,7,34505,80806406,,00]"));
+
+ verifyPosition(decoder, buffer(
"[SG*9059056143*0053*UD,251021,223408,A,41.46500,N,081.53128,W,0.926,000,0,00,70,70,0,50,00000000,0,1,,,,00]"));
verifyPosition(decoder, buffer(
@@ -131,22 +142,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..c83c103c3 100644
--- a/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/WatchProtocolEncoderTest.java
@@ -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 7387f5325..6953784fb 100644
--- a/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WialonProtocolDecoderTest.java
@@ -8,12 +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"));
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"));
+
+ verifyAttributes(decoder, text(
"#D#120319;112003;NA;NA;NA;NA;0.000;NA;NA;0;NA;NA;NA;NA;NA;101_521347:1:521246,101_158:1:510,101_521055:1:510,101_521055_2.9:1:509,101_521056:1:3;626B"));
verifyNull(decoder, text(
diff --git a/src/test/java/org/traccar/protocol/WliFrameDecoderTest.java b/src/test/java/org/traccar/protocol/WliFrameDecoderTest.java
index 2e0d86a61..45c86ae1a 100644
--- a/src/test/java/org/traccar/protocol/WliFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WliFrameDecoderTest.java
@@ -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..e74b1df06 100644
--- a/src/test/java/org/traccar/protocol/WliProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WliProtocolDecoderTest.java
@@ -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..a1cbfe737 100644
--- a/src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WondexFrameDecoderTest.java
@@ -11,7 +11,7 @@ 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..72ba8e163 100644
--- a/src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WondexProtocolDecoderTest.java
@@ -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..f482871dd 100644
--- a/src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/WondexProtocolEncoderTest.java
@@ -10,7 +10,7 @@ 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..b901820fe 100644
--- a/src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/WristbandProtocolDecoderTest.java
@@ -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..34437862c 100644
--- a/src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java
@@ -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..d327930b5
--- /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.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 89c499016..48ba1a691 100644
--- a/src/test/java/org/traccar/protocol/Xexun2ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Xexun2ProtocolDecoderTest.java
@@ -8,7 +8,10 @@ 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"));
verifyPositions(decoder, false, binary(
"FAAF00140004863921033475388000AFB7D203003800380038F9608A7B801E0060820205788A205DF523D97844FDB90443D37844FDB90465CFB4FBF946B0E8CEF639095803F8CC00000002350000004000FA608A7BA81E0060820205788A205DF523D97844FDB90443D2F639095803F8CFB4FBF946B0E8CE7844FDB90465CD00000002350000004000FB608A7BD01E0060820205788A205DF523D97844FDB90443D2F639095803F8CFB4FBF946B0E8CE7844FDB90465CD00000002350000004000FAAF"));
@@ -22,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..483bc85fa
--- /dev/null
+++ b/src/test/java/org/traccar/protocol/Xexun2ProtocolEncoderTest.java
@@ -0,0 +1,29 @@
+package org.traccar.protocol;
+
+import org.junit.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..9bc39fc97 100644
--- a/src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/XexunFrameDecoderTest.java
@@ -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..f7599b4c3 100644
--- a/src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/XexunProtocolDecoderTest.java
@@ -6,9 +6,9 @@ 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..db9c829aa 100644
--- a/src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/XirgoProtocolDecoderTest.java
@@ -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..76e2f960d 100644
--- a/src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/XirgoProtocolEncoderTest.java
@@ -11,7 +11,7 @@ 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..8ed175a74 100644
--- a/src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Xrb28ProtocolDecoderTest.java
@@ -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..a66efecc2 100644
--- a/src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java
+++ b/src/test/java/org/traccar/protocol/Xrb28ProtocolEncoderTest.java
@@ -9,9 +9,9 @@ import static org.junit.Assert.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..007af984e 100644
--- a/src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Xt013ProtocolDecoderTest.java
@@ -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..35cb3c3fa 100644
--- a/src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/Xt2400ProtocolDecoderTest.java
@@ -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..81afe53a3 100644
--- a/src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/YwtProtocolDecoderTest.java
@@ -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..4bf668064 100644
--- a/src/test/java/org/traccar/reports/ReportUtilsTest.java
+++ b/src/test/java/org/traccar/reports/ReportUtilsTest.java
@@ -1,9 +1,20 @@
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.Before;
+import org.junit.Test;
+import org.traccar.BaseTest;
+import org.traccar.api.security.PermissionsService;
+import org.traccar.config.Config;
+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.common.TripsConfig;
+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;
@@ -15,15 +26,23 @@ import java.util.Iterator;
import java.util.List;
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.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class ReportUtilsTest extends BaseTest {
+
+ private Storage storage;
+
+ @Before
+ public void init() throws StorageException {
+ storage = mock(Storage.class);
+ when(storage.getObject(any(), 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 +57,39 @@ 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;
}
-
+
@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(TripsConfig.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),
@@ -79,14 +102,16 @@ public class ReportUtilsTest extends BaseTest {
position("2016-01-01 00:07:00.000", 0, 3000));
TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false, 0.01);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class),
+ tripsConfig, mock(VelocityEngine.class), null);
- Collection<TripReport> trips = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, TripReport.class);
+ var trips = reportUtils.detectTripsAndStops(mock(Device.class), data, false, 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 +120,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.detectTripsAndStops(mock(Device.class) ,data, false, 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());
@@ -118,7 +142,7 @@ public class ReportUtilsTest extends BaseTest {
}
@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),
@@ -133,14 +157,16 @@ public class ReportUtilsTest extends BaseTest {
data.get(5).set(Position.KEY_IGNITION, false);
TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, true, false, 0.01);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class),
+ tripsConfig, mock(VelocityEngine.class), null);
- Collection<TripReport> trips = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, TripReport.class);
+ var trips = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, 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 +175,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.detectTripsAndStops(mock(Device.class) ,data, false, TripReportItem.class);
assertNotNull(trips);
assertFalse(trips.isEmpty());
@@ -164,15 +189,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.detectTripsAndStops(mock(Device.class) ,data, false, 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());
@@ -187,7 +211,7 @@ public class ReportUtilsTest extends BaseTest {
}
@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),
@@ -204,14 +228,16 @@ public class ReportUtilsTest extends BaseTest {
position("2016-01-01 00:11:00.000", 0, 7000));
TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false, 0.01);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class),
+ tripsConfig, mock(VelocityEngine.class), null);
- Collection<TripReport> trips = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, TripReport.class);
+ var trips = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, 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 +246,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.detectTripsAndStops(mock(Device.class) ,data, false, 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());
@@ -243,7 +268,7 @@ public class ReportUtilsTest extends BaseTest {
}
@Test
- public void testDetectStopsOnly() throws ParseException {
+ public void testDetectStopsOnly() throws Exception {
Collection<Position> data = Arrays.asList(
position("2016-01-01 00:00:00.000", 0, 0),
@@ -254,14 +279,16 @@ public class ReportUtilsTest extends BaseTest {
position("2016-01-01 00:05:00.000", 0, 0));
TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class),
+ tripsConfig, mock(VelocityEngine.class), null);
- Collection<StopReport> result = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class);
+ var result = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, 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,7 +297,7 @@ public class ReportUtilsTest extends BaseTest {
}
@Test
- public void testDetectStopsWithTripCut() throws ParseException {
+ public void testDetectStopsWithTripCut() throws Exception {
Collection<Position> data = Arrays.asList(
position("2016-01-01 00:00:00.000", 0, 0),
@@ -281,14 +308,16 @@ public class ReportUtilsTest extends BaseTest {
position("2016-01-01 00:05:00.000", 2, 0));
TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class),
+ tripsConfig, mock(VelocityEngine.class), null);
- Collection<StopReport> result = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class);
+ var result = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, 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,7 +326,7 @@ public class ReportUtilsTest extends BaseTest {
}
@Test
- public void testDetectStopsStartedFromTrip() throws ParseException {
+ public void testDetectStopsStartedFromTrip() throws Exception {
Collection<Position> data = Arrays.asList(
position("2016-01-01 00:00:00.000", 2, 0),
@@ -308,14 +337,16 @@ public class ReportUtilsTest extends BaseTest {
position("2016-01-01 00:05:00.000", 0, 0));
TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class),
+ tripsConfig, mock(VelocityEngine.class), null);
- Collection<StopReport> result = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class);
+ var result = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, 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());
@@ -324,7 +355,7 @@ public class ReportUtilsTest extends BaseTest {
}
@Test
- public void testDetectStopsMoving() throws ParseException {
+ public void testDetectStopsMoving() throws Exception {
Collection<Position> data = Arrays.asList(
position("2016-01-01 00:00:00.000", 5, 0),
@@ -335,9 +366,11 @@ public class ReportUtilsTest extends BaseTest {
position("2016-01-01 00:05:00.000", 5, 0));
TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class),
+ tripsConfig, mock(VelocityEngine.class), null);
- Collection<StopReport> result = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, StopReport.class);
+ var result = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, StopReportItem.class);
assertNotNull(result);
assertTrue(result.isEmpty());
@@ -345,7 +378,7 @@ public class ReportUtilsTest extends BaseTest {
}
@Test
- public void testDetectTripAndStopByGap() throws ParseException {
+ public void testDetectTripAndStopByGap() throws Exception {
Collection<Position> data = Arrays.asList(
position("2016-01-01 00:00:00.000", 7, 100),
@@ -358,14 +391,16 @@ public class ReportUtilsTest extends BaseTest {
position("2016-01-01 00:25:00.000", 5, 900));
TripsConfig tripsConfig = new TripsConfig(500, 200000, 200000, 900000, false, false, 0.01);
+ ReportUtils reportUtils = new ReportUtils(
+ mock(Config.class), storage, mock(PermissionsService.class),
+ tripsConfig, mock(VelocityEngine.class), null);
- Collection<TripReport> trips = ReportUtils.detectTripsAndStops(
- new TestIdentityManager(), null, data, tripsConfig, false, TripReport.class);
+ var trips = reportUtils.detectTripsAndStops(mock(Device.class) ,data, false, 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 +409,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.detectTripsAndStops(mock(Device.class) ,data, false, 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..202983f1e 100644
--- a/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java
+++ b/src/test/java/org/traccar/speedlimit/OverpassSpeedLimitProviderTest.java
@@ -3,19 +3,20 @@ package org.traccar.speedlimit;
import org.junit.Ignore;
import org.junit.Test;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
public class OverpassSpeedLimitProviderTest {
+ private final Client client = ClientBuilder.newClient();
+
@Ignore
@Test
- public void test() throws Exception {
- testLocationProvider();
- }
-
- public void testLocationProvider() throws Exception {
- SpeedLimitProvider provider = new OverpassSpeedLimitProvider("http://8.8.8.8/api/interpreter");
+ 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/swagger.json b/swagger.json
index 5a77e4bf9..3eab9b522 100644
--- a/swagger.json
+++ b/swagger.json
@@ -2,7 +2,7 @@
"openapi": "3.0.1",
"info": {
"title": "Traccar",
- "version": "4.14",
+ "version": "5.5",
"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"
},
@@ -2714,9 +2718,6 @@
"poiLayer": {
"type": "string"
},
- "token": {
- "type": "string"
- },
"attributes": {
"type": "object",
"properties": {}
@@ -2891,6 +2892,10 @@
"type": "integer",
"description": "Geofence Id, can be second parameter only"
},
+ "notificationId": {
+ "type": "integer",
+ "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"
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..9fae1f13b 100644
--- a/templates/full/alarm.vm
+++ b/templates/full/alarm.vm
@@ -3,8 +3,10 @@
<html>
<body>
Device: $device.name<br>
-Alarm: $position.getString("alarm")<br>
+Alarm: $position.getString("alarm")<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..8f2c515b2 100644
--- a/templates/full/deviceOffline.vm
+++ b/templates/full/deviceOffline.vm
@@ -5,6 +5,8 @@
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>
+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/deviceOnline.vm b/templates/full/deviceOnline.vm
index fd17edef0..81a4ccbc8 100644
--- a/templates/full/deviceOnline.vm
+++ b/templates/full/deviceOnline.vm
@@ -5,6 +5,8 @@
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>
+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/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..e012845e6 100644
--- a/templates/full/deviceUnknown.vm
+++ b/templates/full/deviceUnknown.vm
@@ -5,6 +5,8 @@
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>
+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/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/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/config-doc.py b/tools/config-doc.py
new file mode 100755
index 000000000..c55b2b5ef
--- /dev/null
+++ b/tools/config-doc.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python3
+
+import re
+import os
+import argparse
+
+_KEYS_FILE = os.path.join(
+ os.path.dirname(__file__), "../src/main/java/org/traccar/config/Keys.java"
+)
+
+
+def get_config_keys():
+ """Parses Keys.java to extract keys to be used in configuration files
+
+ Args: None
+
+ Returns:
+ list: A list of dict containing the following keys -
+ 'key': A dot separated name of the config key
+ 'description': A list of str
+ """
+ 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:
+ config = re.findall(
+ r"(/\*\*.*?\*/)\n\s+(public static final Config.*?;)", f.read(), re.DOTALL
+ )
+ for i in config:
+ try:
+ key_match = key_match_re.search(i[1])
+ 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")
+ ]
+ 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:
+ # will continue if key_match.group(1) or terms[0] does not exist
+ # for some reason
+ pass
+
+ return keys
+
+
+def get_html():
+ return ("\n").join(
+ [
+ f""" <div class="card mt-3">
+ <div class="card-body">
+ <h5 class="card-title">
+ {x["key"]}
+ </h5>
+ <p class="card-text">
+ {"<br /> ".join(x["description"])}
+ </p>
+ </div>
+ </div>"""
+ for x in get_config_keys()
+ ]
+ )
+
+
+def get_pug():
+ return ("\n").join(
+ [
+ f""" div(class='card mt-3')
+ div(class='card-body')
+ 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()
+ ]
+ )
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(
+ description="Parses Keys.java to extract keys to be used in configuration files"
+ )
+ parser.add_argument(
+ "--format", choices=["pug", "html"], default="pug", help="default: 'pug'"
+ )
+ args = parser.parse_args()
+
+ def get_output():
+ if args.format == 'html':
+ return get_html()
+
+ return get_pug()
+
+ 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..6e310051a 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
diff --git a/tools/test-generator.py b/tools/test-generator.py
index ca7871e1d..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,12 +35,14 @@ for i in range(0, len(waypoints)):
lon = lon1 + (lon2 - lon1) * j / count
points.append((lat, lon))
-def send(conn, lat, lon, course, speed, alarm, ignition, accuracy, rpm, fuel, driverUniqueId):
- params = (('id', id), ('timestamp', int(time.time())), ('lat', lat), ('lon', lon), ('bearing', course), ('speed', speed))
+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:
params = params + (('ignition', 'true'),)
+ else:
+ params = params + (('ignition', 'false'),)
if accuracy:
params = params + (('accuracy', accuracy),)
if rpm:
@@ -49,7 +51,7 @@ def send(conn, lat, lon, course, speed, alarm, ignition, accuracy, rpm, fuel, dr
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):
@@ -68,13 +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
- ignition = (index % len(points)) != 0
+ battery = random.randint(0, 100)
+ 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, 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 55bbf389f..89f1c76ed 100755
--- a/tools/test-integration.py
+++ b/tools/test-integration.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
import sys
import os
@@ -8,6 +8,7 @@ import urllib2
import json
import socket
import time
+import threading
messages = {
'gps103' : 'imei:123456789012345,help me,1201011201,,F,120100.000,A,6000.0000,N,13000.0000,E,0.00,;',
@@ -88,7 +89,36 @@ 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$',
}
baseUrl = 'http://localhost:8082'
@@ -110,7 +140,7 @@ def load_ports():
def login():
request = urllib2.Request(baseUrl + '/api/session')
- response = urllib2.urlopen(request, urllib.urlencode(user))
+ response = urllib2.urlopen(request, urllib.parse.urlencode(user))
if debug:
print '\nlogin: %s\n' % repr(json.load(response))
return response.headers.get('Set-Cookie')
@@ -141,11 +171,12 @@ 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(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')
@@ -155,40 +186,35 @@ def get_protocols(cookie, device_id):
protocols.append(position['protocol'])
return protocols
-ports = load_ports()
+if __name__ == "__main__":
+ ports = load_ports()
-cookie = login()
-remove_devices(cookie)
+ cookie = login()
+ remove_devices(cookie)
-devices = {
- '123456789012345' : add_device(cookie, '123456789012345'),
- '123456789012' : add_device(cookie, '123456789012'),
- '1234567890' : add_device(cookie, '1234567890'),
- '123456' : add_device(cookie, '123456'),
- '1234' : add_device(cookie, '1234')
-}
-
-
-all = set(ports.keys())
-protocols = set(messages.keys())
-
-print 'Total: %d' % len(all)
-print 'Missing: %d' % len(all - protocols)
-print 'Covered: %d' % len(protocols)
+ devices = {
+ '123456789012345' : add_device(cookie, '123456789012345'),
+ '123456789012' : add_device(cookie, '123456789012'),
+ '1234567890' : add_device(cookie, '1234567890'),
+ '123456' : add_device(cookie, '123456'),
+ '1234' : add_device(cookie, '1234')
+ }
-#if all - protocols:
-# print '\nMissing: %s\n' % repr(list((all - protocols)))
+ all = set(ports.keys())
+ protocols = set(messages.keys())
-for protocol in messages:
- send_message(ports[protocol], messages[protocol])
+ print 'Total: %d' % len(all)
+ print 'Missing: %d' % len(all - protocols)
+ print 'Covered: %d' % len(protocols)
-time.sleep(10)
+ for protocol in messages:
+ send_message(ports[protocol], messages[protocol])
-for device in devices:
- protocols -= set(get_protocols(cookie, devices[device]))
+ for device in devices:
+ protocols -= set(get_protocols(cookie, devices[device]))
-print 'Success: %d' % (len(messages) - len(protocols))
-print 'Failed: %d' % len(protocols)
+ print 'Success: %d' % (len(messages) - len(protocols))
+ print 'Failed: %d' % len(protocols)
-if protocols:
- print '\nFailed: %s' % repr(list(protocols))
+ if protocols:
+ print '\nFailed: %s' % repr(list(protocols))
diff --git a/tools/test-map.py b/tools/test-map.py
index c289df605..362c95878 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 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))
return response.headers.get('Set-Cookie')
def add_device(cookie, unique_id):
@@ -29,7 +29,7 @@ def add_device(cookie, unique_id):
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 aac829df866d4975fa52e2d42b4d197ec1f05d3
+Subproject 610ce1e5447d47c316f87887b64c4c459bad855