From 0177128690d52c65d46b56411ff96da62e5388a2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 27 Oct 2016 16:42:05 +1300 Subject: Implement default config (fix #2484) --- setup/default.xml | 442 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 442 insertions(+) create mode 100644 setup/default.xml (limited to 'setup/default.xml') diff --git a/setup/default.xml b/setup/default.xml new file mode 100644 index 000000000..8b1cfaeba --- /dev/null +++ b/setup/default.xml @@ -0,0 +1,442 @@ + + + + + + + + + true + 8082 + ./web + + true + google + + true + all + ./logs/tracker-server.log + + true + true + true + true + true + true + true + + + + org.h2.Driver + jdbc:h2:./data/database + sa + + + true + + ./schema/changelog-master.xml + + + SELECT * FROM server + + + + UPDATE server SET + registration = :registration, + readonly = :readonly, + map = :map, + bingKey = :bingKey, + mapUrl = :mapUrl, + distanceUnit = :distanceUnit, + speedUnit = :speedUnit, + latitude = :latitude, + longitude = :longitude, + zoom = :zoom, + twelveHourFormat = :twelveHourFormat, + attributes = :attributes + WHERE id = :id + + + + SELECT * FROM users + WHERE email = :email + + + + SELECT * FROM users + + + + INSERT INTO users (name, email, hashedPassword, salt, admin, map, distanceUnit, speedUnit, latitude, longitude, zoom, twelveHourFormat, attributes) + VALUES (:name, :email, :hashedPassword, :salt, :admin, :map, :distanceUnit, :speedUnit, :latitude, :longitude, :zoom, :twelveHourFormat, :attributes) + + + + UPDATE users SET + name = :name, + email = :email, + admin = :admin, + map = :map, + distanceUnit = :distanceUnit, + speedUnit = :speedUnit, + latitude = :latitude, + longitude = :longitude, + zoom = :zoom, + twelveHourFormat = :twelveHourFormat, + attributes = :attributes + WHERE id = :id + + + + UPDATE users SET hashedPassword = :hashedPassword, salt = :salt WHERE id = :id + + + + DELETE FROM users WHERE id = :id + + + + SELECT userId, deviceId FROM user_device + + + + SELECT userId, groupId FROM user_group + + + + SELECT * FROM devices + + + + INSERT INTO devices (name, uniqueId, groupId, attributes, phone, model, contact, category) + VALUES (:name, :uniqueId, :groupId, :attributes, :phone, :model, :contact, :category) + + + + UPDATE devices SET + name = :name, + uniqueId = :uniqueId, + groupId = :groupId, + attributes = :attributes, + phone = :phone, + model = :model, + contact = :contact, + category = :category + WHERE id = :id + + + + UPDATE devices SET lastUpdate = :lastUpdate WHERE id = :id + + + + DELETE FROM devices WHERE id = :id + + + + INSERT INTO user_device (userId, deviceId) VALUES (:userId, :deviceId) + + + + DELETE FROM user_device WHERE userId = :userId AND deviceId = :deviceId + + + + SELECT * FROM groups + + + + INSERT INTO groups (name, groupId, attributes) VALUES (:name, :groupId, :attributes) + + + + UPDATE groups SET name = :name, groupId = :groupId, attributes = :attributes WHERE id = :id + + + + DELETE FROM groups WHERE id = :id + + + + INSERT INTO user_group (userId, groupId) VALUES (:userId, :groupId) + + + + DELETE FROM user_group WHERE userId = :userId AND groupId = :groupId + + + + SELECT * FROM positions WHERE deviceId = :deviceId AND fixTime BETWEEN :from AND :to ORDER BY fixTime + + + + INSERT INTO positions (deviceId, protocol, serverTime, deviceTime, fixTime, valid, latitude, longitude, altitude, speed, course, address, attributes) + VALUES (:deviceId, :protocol, :now, :deviceTime, :fixTime, :valid, :latitude, :longitude, :altitude, :speed, :course, :address, :attributes) + + + + SELECT * FROM positions WHERE id IN (SELECT positionId FROM devices) + + + + UPDATE devices SET positionId = :id WHERE id = :deviceId + + + + SELECT * FROM events WHERE id = :id + + + + INSERT INTO events (type, serverTime, deviceId, positionId, geofenceId, attributes) + VALUES (:type, :serverTime, :deviceId, :positionId, :geofenceId, :attributes) + + + + SELECT * FROM events WHERE deviceId = :deviceId AND serverTime BETWEEN :from AND :to ORDER BY serverTime + + + + SELECT * FROM geofences + + + + INSERT INTO geofences (name, description, area, attributes) + VALUES (:name, :description, :area, :attributes) + + + + UPDATE geofences SET + name = :name, + description = :description, + area = :area, + attributes = :attributes + WHERE id = :id + + + + DELETE FROM geofences WHERE id = :id + + + + SELECT userId, geofenceId FROM user_geofence + + + + INSERT INTO user_geofence (userId, geofenceId) VALUES (:userId, :geofenceId) + + + + DELETE FROM user_geofence WHERE userId = :userId AND geofenceId = :geofenceId + + + + SELECT groupId, geofenceId FROM group_geofence + + + + INSERT INTO group_geofence (groupId, geofenceId) VALUES (:groupId, :geofenceId) + + + + DELETE FROM group_geofence WHERE groupId = :groupId AND geofenceId = :geofenceId + + + + SELECT deviceId, geofenceId FROM device_geofence + + + + INSERT INTO device_geofence (deviceId, geofenceId) VALUES (:deviceId, :geofenceId) + + + + DELETE FROM device_geofence WHERE deviceId = :deviceId AND geofenceId = :geofenceId + + + + SELECT * FROM notifications + + + + INSERT INTO notifications (userId, type, attributes) + VALUES (:userId, :type, :attributes) + + + + UPDATE notifications SET + userId = :userId, + type = :type, + attributes = :attributes + WHERE id = :id + + + + DELETE FROM notifications WHERE id = :id + + + + DELETE FROM positions WHERE serverTime < :serverTime AND id NOT IN (SELECT positionId FROM devices) + + + + SELECT * FROM attribute_aliases + + + + INSERT INTO attribute_aliases (deviceId, attribute, alias) + VALUES (:deviceId, :attribute, :alias) + + + + UPDATE attribute_aliases SET + deviceId = :deviceId, + attribute = :attribute, + alias = :alias + WHERE id = :id + + + + DELETE FROM attribute_aliases WHERE id = :id + + + + SELECT * FROM statistics WHERE captureTime BETWEEN :from AND :to ORDER BY captureTime + + + + INSERT INTO statistics (captureTime, activeUsers, activeDevices, requests, messagesReceived, messagesStored, attributes) + VALUES (:captureTime, :activeUsers, :activeDevices, :requests, :messagesReceived, :messagesStored, :attributes) + + + + + 5001 + 5002 + 5003 + 5004 + 5005 + 5006 + false + 5007 + 5008 + 5009 + 5010 + 5011 + 5012 + 5013 + 5014 + 5015 + 5016 + 5017 + 5018 + 5019 + 5020 + 5021 + 5022 + 5023 + 5024 + 5025 + 5026 + 5027 + 5028 + 5029 + 5030 + 5031 + 5032 + 5033 + 5034 + 5035 + 5036 + 5037 + 5038 + 5039 + 5040 + 5041 + 5042 + 5043 + 5044 + 5045 + 5046 + 5047 + 5048 + 5049 + 5050 + 5051 + 5052 + 5053 + 5054 + 5055 + 5056 + 5057 + 5058 + 5059 + 5060 + 5061 + 5062 + 5063 + 5064 + 5065 + 5066 + 5067 + 5068 + 5069 + 5070 + 5071 + 5072 + 5073 + 5074 + 5075 + 5076 + 5077 + 5078 + 5079 + 5080 + 5081 + 5082 + 5083 + 5084 + 5085 + 5086 + 5087 + 5088 + 5089 + 5090 + 5091 + 5092 + 5093 + 5094 + 5095 + 5096 + 5097 + 5098 + 5099 + 5100 + 5101 + 5102 + 5103 + 5104 + 5105 + 5106 + 5107 + 5108 + 5109 + 5110 + 5111 + 5112 + 5113 + 5114 + 5115 + 5116 + 5117 + 5118 + 5119 + 5120 + 5121 + 5122 + 5123 + 5124 + 5125 + 5126 + 5127 + + -- cgit v1.2.3 From cfb6bfcb4f7cf945f749634ccfc981e63dba6022 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 31 Oct 2016 03:57:15 +1300 Subject: Remove database config from default --- debug.xml | 68 ------------------------------------------------------- setup/default.xml | 5 ---- setup/traccar.xml | 5 ++++ 3 files changed, 5 insertions(+), 73 deletions(-) (limited to 'setup/default.xml') diff --git a/debug.xml b/debug.xml index 31f38c356..05eac10da 100644 --- a/debug.xml +++ b/debug.xml @@ -6,87 +6,19 @@ ./setup/default.xml - - - true - 8082 ./traccar-web/web true true - - false - nominatim - http://nominatim.openstreetmap.org/reverse - - false - fake - 260 - 2 - - - - - true - all target/tracker-server.log - - - - - - - - - - - - - - - - - - - - org.h2.Driver jdbc:h2:./target/database sa - true - - ./schema/changelog-master.xml - - - - - 6037 diff --git a/setup/default.xml b/setup/default.xml index 8b1cfaeba..f50f3904f 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -27,11 +27,6 @@ - org.h2.Driver - jdbc:h2:./data/database - sa - - true ./schema/changelog-master.xml diff --git a/setup/traccar.xml b/setup/traccar.xml index e4b3e9167..9b9bfa289 100644 --- a/setup/traccar.xml +++ b/setup/traccar.xml @@ -6,4 +6,9 @@ ./conf/default.xml + org.h2.Driver + jdbc:h2:./data/database + sa + + -- cgit v1.2.3 From af6c734879aa483efcc8150d5fdb704f40fb59cd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 17 Nov 2016 22:48:33 +1300 Subject: Add user expiration and device limit --- schema/changelog-3.8.xml | 10 ++++++ setup/default.xml | 8 +++-- src/org/traccar/api/SecurityRequestFilter.java | 2 +- src/org/traccar/api/resource/DeviceResource.java | 7 ++++ src/org/traccar/api/resource/SessionResource.java | 2 +- src/org/traccar/api/resource/UserResource.java | 11 ++++--- src/org/traccar/database/PermissionsManager.java | 6 ++-- src/org/traccar/model/User.java | 40 +++++++++++++++++++++++ 8 files changed, 75 insertions(+), 11 deletions(-) (limited to 'setup/default.xml') diff --git a/schema/changelog-3.8.xml b/schema/changelog-3.8.xml index 780a2d029..ba591f192 100644 --- a/schema/changelog-3.8.xml +++ b/schema/changelog-3.8.xml @@ -107,5 +107,15 @@ + + + + + + + + + + diff --git a/setup/default.xml b/setup/default.xml index f50f3904f..a9d7684d4 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -62,8 +62,8 @@ - INSERT INTO users (name, email, hashedPassword, salt, admin, map, distanceUnit, speedUnit, latitude, longitude, zoom, twelveHourFormat, attributes) - VALUES (:name, :email, :hashedPassword, :salt, :admin, :map, :distanceUnit, :speedUnit, :latitude, :longitude, :zoom, :twelveHourFormat, :attributes) + INSERT INTO users (name, email, hashedPassword, salt, admin, map, distanceUnit, speedUnit, latitude, longitude, zoom, twelveHourFormat, coordinateFormat, disabled, expirationTime, deviceLimit, attributes) + VALUES (:name, :email, :hashedPassword, :salt, :admin, :map, :distanceUnit, :speedUnit, :latitude, :longitude, :zoom, :twelveHourFormat, :coordinateFormat, :disabled, :expirationTime, :deviceLimit, :attributes) @@ -78,6 +78,10 @@ longitude = :longitude, zoom = :zoom, twelveHourFormat = :twelveHourFormat, + coordinateFormat = :coordinateFormat, + disabled = :disabled, + expirationTime = :expirationTime, + deviceLimit = :deviceLimit, attributes = :attributes WHERE id = :id diff --git a/src/org/traccar/api/SecurityRequestFilter.java b/src/org/traccar/api/SecurityRequestFilter.java index fd4c77525..598e4566d 100644 --- a/src/org/traccar/api/SecurityRequestFilter.java +++ b/src/org/traccar/api/SecurityRequestFilter.java @@ -67,7 +67,7 @@ public class SecurityRequestFilter implements ContainerRequestFilter { try { String[] auth = decodeBasicAuth(authHeader); - User user = Context.getDataManager().login(auth[0], auth[1]); + User user = Context.getPermissionsManager().login(auth[0], auth[1]); if (user != null) { Context.getStatisticsManager().registerRequest(user.getId()); securityContext = new UserSecurityContext(new UserPrincipal(user.getId())); diff --git a/src/org/traccar/api/resource/DeviceResource.java b/src/org/traccar/api/resource/DeviceResource.java index f20ed86ad..0b389ede1 100644 --- a/src/org/traccar/api/resource/DeviceResource.java +++ b/src/org/traccar/api/resource/DeviceResource.java @@ -58,6 +58,13 @@ public class DeviceResource extends BaseResource { @POST public Response add(Device entity) throws SQLException { Context.getPermissionsManager().checkReadonly(getUserId()); + int deviceLimit = Context.getPermissionsManager().getUser(getUserId()).getDeviceLimit(); + if (deviceLimit != 0) { + int deviceCount = Context.getPermissionsManager().getDevicePermissions(getUserId()).size(); + if (deviceCount >= deviceLimit) { + throw new SecurityException("User device limit reached"); + } + } Context.getDeviceManager().addDevice(entity); Context.getDataManager().linkDevice(getUserId(), entity.getId()); Context.getPermissionsManager().refreshPermissions(); diff --git a/src/org/traccar/api/resource/SessionResource.java b/src/org/traccar/api/resource/SessionResource.java index 2847e41c1..a459186fe 100644 --- a/src/org/traccar/api/resource/SessionResource.java +++ b/src/org/traccar/api/resource/SessionResource.java @@ -64,7 +64,7 @@ public class SessionResource extends BaseResource { } } if (email != null && password != null) { - User user = Context.getDataManager().login(email, password); + User user = Context.getPermissionsManager().login(email, password); if (user != null) { userId = user.getId(); request.getSession().setAttribute(USER_ID_KEY, userId); diff --git a/src/org/traccar/api/resource/UserResource.java b/src/org/traccar/api/resource/UserResource.java index f0a8597cc..c6e84c918 100644 --- a/src/org/traccar/api/resource/UserResource.java +++ b/src/org/traccar/api/resource/UserResource.java @@ -60,13 +60,16 @@ public class UserResource extends BaseResource { @Path("{id}") @PUT public Response update(@PathParam("id") long id, User entity) throws SQLException { - if (entity.getAdmin()) { + User old = Context.getPermissionsManager().getUser(entity.getId()); + if (old.getExpirationTime() == null && entity.getExpirationTime() != null + || old.getExpirationTime() != null && !old.getExpirationTime().equals(entity.getExpirationTime()) + || old.getAdmin() != entity.getAdmin() + || old.getReadonly() != entity.getReadonly() + || old.getDisabled() != entity.getDisabled() + || old.getDeviceLimit() != entity.getDeviceLimit()) { Context.getPermissionsManager().checkAdmin(getUserId()); } else { Context.getPermissionsManager().checkUser(getUserId(), entity.getId()); - if (!entity.getReadonly()) { - Context.getPermissionsManager().checkReadonly(entity.getId()); - } } Context.getPermissionsManager().updateUser(entity); if (Context.getNotificationManager() != null) { diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java index b0ae504d0..e620d5334 100644 --- a/src/org/traccar/database/PermissionsManager.java +++ b/src/org/traccar/database/PermissionsManager.java @@ -217,11 +217,11 @@ public class PermissionsManager { public User login(String email, String password) throws SQLException { User user = dataManager.login(email, password); - if (user != null && users.get(user.getId()) != null) { + if (user != null && !user.getDisabled() && (user.getExpirationTime() == null + || user.getExpirationTime().getTime() > System.currentTimeMillis())) { return users.get(user.getId()); - } else { - return null; } + return null; } } diff --git a/src/org/traccar/model/User.java b/src/org/traccar/model/User.java index aa0b33713..a36fa0e31 100644 --- a/src/org/traccar/model/User.java +++ b/src/org/traccar/model/User.java @@ -18,6 +18,8 @@ package org.traccar.model; import com.fasterxml.jackson.annotation.JsonIgnore; import org.traccar.helper.Hashing; +import java.util.Date; + public class User extends Extensible { private String name; @@ -140,6 +142,44 @@ public class User extends Extensible { this.coordinateFormat = coordinateFormat; } + private boolean disabled; + + public boolean getDisabled() { + return disabled; + } + + public void setDisabled(boolean disabled) { + this.disabled = disabled; + } + + private Date expirationTime; + + public Date getExpirationTime() { + if (expirationTime != null) { + return new Date(expirationTime.getTime()); + } else { + return null; + } + } + + public void setExpirationTime(Date expirationTime) { + if (expirationTime != null) { + this.expirationTime = new Date(expirationTime.getTime()); + } else { + this.expirationTime = null; + } + } + + private int deviceLimit; + + public int getDeviceLimit() { + return deviceLimit; + } + + public void setDeviceLimit(int deviceLimit) { + this.deviceLimit = deviceLimit; + } + public String getPassword() { return null; } -- cgit v1.2.3 From c9b67d19132b687bea9130f39f13a5515b120e5e Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Fri, 18 Nov 2016 16:05:35 +0500 Subject: Implement users tokens --- schema/changelog-3.8.xml | 5 +++++ setup/default.xml | 5 +++-- src/org/traccar/api/resource/SessionResource.java | 6 ++++++ src/org/traccar/api/resource/UserResource.java | 3 ++- src/org/traccar/database/PermissionsManager.java | 26 +++++++++++++++++++++++ src/org/traccar/model/User.java | 25 ++++++++++++++++++++++ 6 files changed, 67 insertions(+), 3 deletions(-) (limited to 'setup/default.xml') diff --git a/schema/changelog-3.8.xml b/schema/changelog-3.8.xml index ba591f192..f53673eae 100644 --- a/schema/changelog-3.8.xml +++ b/schema/changelog-3.8.xml @@ -116,6 +116,11 @@ + + + + + diff --git a/setup/default.xml b/setup/default.xml index a9d7684d4..e6d701f4c 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -62,8 +62,8 @@ - INSERT INTO users (name, email, hashedPassword, salt, admin, map, distanceUnit, speedUnit, latitude, longitude, zoom, twelveHourFormat, coordinateFormat, disabled, expirationTime, deviceLimit, attributes) - VALUES (:name, :email, :hashedPassword, :salt, :admin, :map, :distanceUnit, :speedUnit, :latitude, :longitude, :zoom, :twelveHourFormat, :coordinateFormat, :disabled, :expirationTime, :deviceLimit, :attributes) + INSERT INTO users (name, email, hashedPassword, salt, admin, map, distanceUnit, speedUnit, latitude, longitude, zoom, twelveHourFormat, coordinateFormat, disabled, expirationTime, deviceLimit, token, attributes) + VALUES (:name, :email, :hashedPassword, :salt, :admin, :map, :distanceUnit, :speedUnit, :latitude, :longitude, :zoom, :twelveHourFormat, :coordinateFormat, :disabled, :expirationTime, :deviceLimit, :token, :attributes) @@ -82,6 +82,7 @@ disabled = :disabled, expirationTime = :expirationTime, deviceLimit = :deviceLimit, + token = :token, attributes = :attributes WHERE id = :id diff --git a/src/org/traccar/api/resource/SessionResource.java b/src/org/traccar/api/resource/SessionResource.java index a61738c7e..6c5263123 100644 --- a/src/org/traccar/api/resource/SessionResource.java +++ b/src/org/traccar/api/resource/SessionResource.java @@ -69,6 +69,12 @@ public class SessionResource extends BaseResource { userId = user.getId(); request.getSession().setAttribute(USER_ID_KEY, userId); } + } else if (request.getParameter("token") != null) { + User user = Context.getPermissionsManager().getUserByToken(request.getParameter("token")); + if (user != null) { + userId = user.getId(); + request.getSession().setAttribute(USER_ID_KEY, userId); + } } } diff --git a/src/org/traccar/api/resource/UserResource.java b/src/org/traccar/api/resource/UserResource.java index c6e84c918..094de2812 100644 --- a/src/org/traccar/api/resource/UserResource.java +++ b/src/org/traccar/api/resource/UserResource.java @@ -66,7 +66,8 @@ public class UserResource extends BaseResource { || old.getAdmin() != entity.getAdmin() || old.getReadonly() != entity.getReadonly() || old.getDisabled() != entity.getDisabled() - || old.getDeviceLimit() != entity.getDeviceLimit()) { + || old.getDeviceLimit() != entity.getDeviceLimit() + || !old.getToken().equals(entity.getToken())) { Context.getPermissionsManager().checkAdmin(getUserId()); } else { Context.getPermissionsManager().checkUser(getUserId(), entity.getId()); diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java index 1c995a11d..269dfc7bf 100644 --- a/src/org/traccar/database/PermissionsManager.java +++ b/src/org/traccar/database/PermissionsManager.java @@ -29,6 +29,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -39,6 +40,7 @@ public class PermissionsManager { private volatile Server server; private final Map users = new ConcurrentHashMap<>(); + private final Map usersTokens = new HashMap<>(); private final Map> groupPermissions = new HashMap<>(); private final Map> devicePermissions = new HashMap<>(); @@ -81,10 +83,14 @@ public class PermissionsManager { public final void refreshUsers() { users.clear(); + usersTokens.clear(); try { server = dataManager.getServer(); for (User user : dataManager.getUsers()) { users.put(user.getId(), user); + if (user.getToken() != null) { + usersTokens.put(user.getId(), user.getToken()); + } } } catch (SQLException error) { Log.warning(error); @@ -210,18 +216,27 @@ public class PermissionsManager { public void addUser(User user) throws SQLException { dataManager.addUser(user); users.put(user.getId(), user); + if (user.getToken() != null) { + usersTokens.put(user.getId(), user.getToken()); + } refreshPermissions(); } public void updateUser(User user) throws SQLException { dataManager.updateUser(user); users.put(user.getId(), user); + if (user.getToken() != null) { + usersTokens.put(user.getId(), user.getToken()); + } else if (usersTokens.containsKey(user.getId())) { + usersTokens.remove(user.getId()); + } refreshPermissions(); } public void removeUser(long userId) throws SQLException { dataManager.removeUser(userId); users.remove(userId); + usersTokens.remove(userId); refreshPermissions(); } @@ -234,4 +249,15 @@ public class PermissionsManager { return null; } + public User getUserByToken(String token) { + if (usersTokens.containsValue(token)) { + for (Entry entry : usersTokens.entrySet()) { + if (entry.getValue().equals(token)) { + return users.get(entry.getKey()); + } + } + } + return null; + } + } diff --git a/src/org/traccar/model/User.java b/src/org/traccar/model/User.java index a36fa0e31..816f49da9 100644 --- a/src/org/traccar/model/User.java +++ b/src/org/traccar/model/User.java @@ -180,6 +180,31 @@ public class User extends Extensible { this.deviceLimit = deviceLimit; } + private String token; + + public String getToken() { + return token; + } + + public void setToken(String token) { + if (token != null && !token.isEmpty()) { + if (validateToken(token)) { + this.token = token; + } else { + throw new IllegalArgumentException("Bad token"); + } + } else { + this.token = null; + } + } + + public static boolean validateToken(String token) { + if (token.length() < 16 || !token.matches("^[a-zA-Z0-9]+$")) { + return false; + } + return true; + } + public String getPassword() { return null; } -- cgit v1.2.3 From 1861e896418a284dbbccfa55db7add1036bb94ba Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Tue, 22 Nov 2016 12:18:19 +0500 Subject: Implement maintenance event --- setup/default.xml | 2 + src/org/traccar/BasePipelineFactory.java | 9 +++ .../traccar/events/MaintenanceEventHandler.java | 70 ++++++++++++++++++++++ src/org/traccar/model/Event.java | 2 + 4 files changed, 83 insertions(+) create mode 100644 src/org/traccar/events/MaintenanceEventHandler.java (limited to 'setup/default.xml') diff --git a/setup/default.xml b/setup/default.xml index e6d701f4c..d6f8a1752 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -24,6 +24,8 @@ true true true + true + true diff --git a/src/org/traccar/BasePipelineFactory.java b/src/org/traccar/BasePipelineFactory.java index 22bb80ca1..d73b022ae 100644 --- a/src/org/traccar/BasePipelineFactory.java +++ b/src/org/traccar/BasePipelineFactory.java @@ -32,6 +32,7 @@ import org.jboss.netty.handler.timeout.IdleStateHandler; import org.traccar.events.CommandResultEventHandler; import org.traccar.events.GeofenceEventHandler; import org.traccar.events.IgnitionEventHandler; +import org.traccar.events.MaintenanceEventHandler; import org.traccar.events.MotionEventHandler; import org.traccar.events.OverspeedEventHandler; import org.traccar.events.AlertEventHandler; @@ -58,6 +59,7 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory { private GeofenceEventHandler geofenceEventHandler; private AlertEventHandler alertEventHandler; private IgnitionEventHandler ignitionEventHandler; + private MaintenanceEventHandler maintenanceEventHandler; private static final class OpenChannelHandler extends SimpleChannelHandler { @@ -164,6 +166,9 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory { if (Context.getConfig().getBoolean("event.ignitionHandler")) { ignitionEventHandler = new IgnitionEventHandler(); } + if (Context.getConfig().getBoolean("event.maintenanceHandler")) { + maintenanceEventHandler = new MaintenanceEventHandler(); + } } protected abstract void addSpecificHandlers(ChannelPipeline pipeline); @@ -242,6 +247,10 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory { pipeline.addLast("IgnitionEventHandler", ignitionEventHandler); } + if (maintenanceEventHandler != null) { + pipeline.addLast("MaintenanceEventHandler", maintenanceEventHandler); + } + pipeline.addLast("mainHandler", new MainEventHandler()); return pipeline; } diff --git a/src/org/traccar/events/MaintenanceEventHandler.java b/src/org/traccar/events/MaintenanceEventHandler.java new file mode 100644 index 000000000..078848b86 --- /dev/null +++ b/src/org/traccar/events/MaintenanceEventHandler.java @@ -0,0 +1,70 @@ +/* + * 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.events; + +import java.util.ArrayList; +import java.util.Collection; + +import org.traccar.BaseEventHandler; +import org.traccar.Context; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Position; + +public class MaintenanceEventHandler extends BaseEventHandler { + + public static final String ATTRIBUTE_MAINTENANCE_START = "device.maintenanceStart"; + public static final String ATTRIBUTE_MAINTENANCE_INTERVAL = "device.maintenanceInterval"; + + @Override + protected Collection analyzePosition(Position position) { + Device device = Context.getIdentityManager().getDeviceById(position.getDeviceId()); + if (device == null || !Context.getIdentityManager().isLatestPosition(position)) { + return null; + } + + double maintenanceInterval = Context.getDeviceManager() + .lookupServerDouble(device.getId(), ATTRIBUTE_MAINTENANCE_INTERVAL, 0); + if (maintenanceInterval == 0) { + return null; + } + double maintenanceStart = Context.getDeviceManager() + .lookupServerDouble(device.getId(), ATTRIBUTE_MAINTENANCE_START, 0); + + Collection events = new ArrayList<>(); + double oldTotalDistance = 0.0; + double newTotalDistance = 0.0; + + Position lastPosition = Context.getIdentityManager().getLastPosition(position.getDeviceId()); + if (lastPosition != null && lastPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE)) { + oldTotalDistance = ((Number) lastPosition.getAttributes().get(Position.KEY_TOTAL_DISTANCE)).doubleValue(); + } + + if (position.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE)) { + newTotalDistance = ((Number) position.getAttributes().get(Position.KEY_TOTAL_DISTANCE)).doubleValue(); + } + + oldTotalDistance -= maintenanceStart; + newTotalDistance -= maintenanceStart; + if ((long) (oldTotalDistance / maintenanceInterval) < (long) (newTotalDistance / maintenanceInterval)) { + events.add(new Event(Event.TYPE_MAINTENANCE_NEED, position.getDeviceId(), position.getId())); + } + + return events; + } + +} diff --git a/src/org/traccar/model/Event.java b/src/org/traccar/model/Event.java index cdb79f04d..ad861c570 100644 --- a/src/org/traccar/model/Event.java +++ b/src/org/traccar/model/Event.java @@ -55,6 +55,8 @@ public class Event extends Message { public static final String TYPE_IGNITION_ON = "ignitionOn"; public static final String TYPE_IGNITION_OFF = "ignitionOff"; + public static final String TYPE_MAINTENANCE_NEED = "maintenanceNeed"; + private Date serverTime; public Date getServerTime() { -- cgit v1.2.3 From 04f33e6ba29b3a73a65b081d2a8b6ac3e0e0ebee Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 24 Nov 2016 15:52:52 +1300 Subject: Implement Teltonika AT200 protocol --- setup/default.xml | 1 + src/org/traccar/protocol/At2000FrameDecoder.java | 57 +++++++++ src/org/traccar/protocol/At2000Protocol.java | 42 +++++++ .../traccar/protocol/At2000ProtocolDecoder.java | 134 +++++++++++++++++++++ .../traccar/protocol/At2000FrameDecoderTest.java | 26 ++++ .../protocol/At2000ProtocolDecoderTest.java | 24 ++++ 6 files changed, 284 insertions(+) create mode 100644 src/org/traccar/protocol/At2000FrameDecoder.java create mode 100644 src/org/traccar/protocol/At2000Protocol.java create mode 100644 src/org/traccar/protocol/At2000ProtocolDecoder.java create mode 100644 test/org/traccar/protocol/At2000FrameDecoderTest.java create mode 100644 test/org/traccar/protocol/At2000ProtocolDecoderTest.java (limited to 'setup/default.xml') diff --git a/setup/default.xml b/setup/default.xml index d6f8a1752..869c077cf 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -440,5 +440,6 @@ 5125 5126 5127 + 5128 diff --git a/src/org/traccar/protocol/At2000FrameDecoder.java b/src/org/traccar/protocol/At2000FrameDecoder.java new file mode 100644 index 000000000..d0be3f5f4 --- /dev/null +++ b/src/org/traccar/protocol/At2000FrameDecoder.java @@ -0,0 +1,57 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.handler.codec.frame.FrameDecoder; + +public class At2000FrameDecoder extends FrameDecoder { + + private static final int BLOCK_LENGTH = 16; + + private boolean firstPacket = true; + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf) throws Exception { + + if (buf.readableBytes() < 5) { + return null; + } + + int length; + if (firstPacket) { + firstPacket = false; + length = buf.getUnsignedMedium(buf.readerIndex() + 2); + } else { + length = buf.getUnsignedMedium(buf.readerIndex() + 1); + } + + length += BLOCK_LENGTH; + if (length % BLOCK_LENGTH != 0) { + length = (length / BLOCK_LENGTH + 1) * BLOCK_LENGTH; + } + + if (buf.readableBytes() >= length) { + return buf.readBytes(length); + } + + return null; + } + +} diff --git a/src/org/traccar/protocol/At2000Protocol.java b/src/org/traccar/protocol/At2000Protocol.java new file mode 100644 index 000000000..418619cb4 --- /dev/null +++ b/src/org/traccar/protocol/At2000Protocol.java @@ -0,0 +1,42 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.jboss.netty.bootstrap.ServerBootstrap; +import org.jboss.netty.channel.ChannelPipeline; +import org.traccar.BaseProtocol; +import org.traccar.TrackerServer; + +import java.util.List; + +public class At2000Protocol extends BaseProtocol { + + public At2000Protocol() { + super("at2000"); + } + + @Override + public void initTrackerServers(List serverList) { + serverList.add(new TrackerServer(new ServerBootstrap(), getName()) { + @Override + protected void addSpecificHandlers(ChannelPipeline pipeline) { + pipeline.addLast("frameDecoder", new At2000FrameDecoder()); + pipeline.addLast("objectDecoder", new At2000ProtocolDecoder(At2000Protocol.this)); + } + }); + } + +} diff --git a/src/org/traccar/protocol/At2000ProtocolDecoder.java b/src/org/traccar/protocol/At2000ProtocolDecoder.java new file mode 100644 index 000000000..17da0eef7 --- /dev/null +++ b/src/org/traccar/protocol/At2000ProtocolDecoder.java @@ -0,0 +1,134 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.helper.UnitsConverter; +import org.traccar.model.Position; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.xml.bind.DatatypeConverter; +import java.net.SocketAddress; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +public class At2000ProtocolDecoder extends BaseProtocolDecoder { + + private static final int BLOCK_LENGTH = 16; + + public At2000ProtocolDecoder(At2000Protocol protocol) { + super(protocol); + } + + public static final int MSG_ACKNOWLEDGEMENT = 0x00; + public static final int MSG_DEVICE_ID = 0x01; + public static final int MSG_TRACK_REQUEST = 0x88; + public static final int MSG_TRACK_RESPONSE = 0x89; + public static final int MSG_SESSION_END = 0x0c; + + private Cipher cipher; + + private static void sendResponse(Channel channel) { + if (channel != null) { + ChannelBuffer response = ChannelBuffers.directBuffer(BLOCK_LENGTH); + response.writeByte(MSG_ACKNOWLEDGEMENT); + response.writeMedium(1); + response.writeByte(0x00); // success + response.writerIndex(BLOCK_LENGTH); + channel.write(response); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ChannelBuffer buf = (ChannelBuffer) msg; + + if (buf.getUnsignedByte(buf.readerIndex()) == 0x01) { + buf.readUnsignedByte(); // codec id + } + + int type = buf.readUnsignedByte(); + buf.readUnsignedMedium(); // length + buf.skipBytes(BLOCK_LENGTH - 1 - 3); + + if (type == MSG_DEVICE_ID) { + + String imei = buf.readBytes(15).toString(StandardCharsets.US_ASCII); + if (getDeviceSession(channel, remoteAddress, imei) != null) { + + byte[] iv = new byte[BLOCK_LENGTH]; + buf.readBytes(iv); + IvParameterSpec ivSpec = new IvParameterSpec(iv); + + SecretKeySpec keySpec = new SecretKeySpec( + DatatypeConverter.parseHexBinary("000102030405060708090a0b0c0d0e0f"), "AES"); + + cipher = Cipher.getInstance("AES/CBC/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); + + byte[] data = new byte[BLOCK_LENGTH]; + buf.readBytes(data); + cipher.update(data); + + } + + } else if (type == MSG_TRACK_RESPONSE) { + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress); + if (deviceSession == null) { + return null; + } + + Position position = new Position(); + position.setProtocol(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + byte[] data = new byte[buf.capacity() - BLOCK_LENGTH]; + buf.readBytes(data); + buf = ChannelBuffers.wrappedBuffer(ByteOrder.LITTLE_ENDIAN, cipher.update(data)); + + buf.readUnsignedShort(); // index + buf.readUnsignedShort(); // reserved + + position.setValid(true); + + position.setTime(new Date(buf.readLong() * 1000)); + + position.setLatitude(buf.readFloat()); + position.setLongitude(buf.readFloat()); + position.setAltitude(buf.readFloat()); + position.setSpeed(UnitsConverter.knotsFromKph(buf.readFloat())); + position.setCourse(buf.readFloat()); + + return position; + + } + + sendResponse(channel); + + return null; + } + +} diff --git a/test/org/traccar/protocol/At2000FrameDecoderTest.java b/test/org/traccar/protocol/At2000FrameDecoderTest.java new file mode 100644 index 000000000..c7a3dc0b1 --- /dev/null +++ b/test/org/traccar/protocol/At2000FrameDecoderTest.java @@ -0,0 +1,26 @@ +package org.traccar.protocol; + +import org.junit.Assert; +import org.junit.Test; +import org.traccar.ProtocolTest; + +import java.nio.ByteOrder; + +public class At2000FrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + At2000FrameDecoder decoder = new At2000FrameDecoder(); + + Assert.assertEquals( + binary(ByteOrder.LITTLE_ENDIAN, "01012f00000000000000000000000000003335363137333036343430373439320fad981997ae8e031fe10c0ea7641903ca32c0331df467233d2a9cd886fbeef8"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "01012f00000000000000000000000000003335363137333036343430373439320fad981997ae8e031fe10c0ea7641903ca32c0331df467233d2a9cd886fbeef8"))); + + Assert.assertEquals( + binary(ByteOrder.LITTLE_ENDIAN, "893f0000000000000000000000000000e048b1a31deba3f5dbe8877f574877e6ed4d022b6611a10d80dfc4c0c11fa8aacf4a9de61528327e2b66843dd9c5d3a7cc9ee1d9c71a34bb482145d88b4fda3e"), + decoder.decode(null, null, binary(ByteOrder.LITTLE_ENDIAN, "893f0000000000000000000000000000e048b1a31deba3f5dbe8877f574877e6ed4d022b6611a10d80dfc4c0c11fa8aacf4a9de61528327e2b66843dd9c5d3a7cc9ee1d9c71a34bb482145d88b4fda3e"))); + + } + +} diff --git a/test/org/traccar/protocol/At2000ProtocolDecoderTest.java b/test/org/traccar/protocol/At2000ProtocolDecoderTest.java new file mode 100644 index 000000000..14c6920d0 --- /dev/null +++ b/test/org/traccar/protocol/At2000ProtocolDecoderTest.java @@ -0,0 +1,24 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class At2000ProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + At2000ProtocolDecoder decoder = new At2000ProtocolDecoder(new At2000Protocol()); + + verifyNothing(decoder, binary( + "01012f00000000000000000000000000003335363137333036343430373439320fad981997ae8e031fe10c0ea7641903ca32c0331df467233d2a9cd886fbeef8")); + + verifyPosition(decoder, binary( + "893f0000000000000000000000000000e048b1a31deba3f5dbe8877f574877e6ed4d022b6611a10d80dfc4c0c11fa8aacf4a9de61528327e2b66843dd9c5d3a7cc9ee1d9c71a34bb482145d88b4fda3e")); + + verifyNothing(decoder, binary( + "01012f00000000000000000000000000003335373435343037313632363831345612da3748bede02ea4faf04ac02f420c0ff37719eccf2864fa2b8191abf8242")); + + } + +} -- cgit v1.2.3 From b0068d87ddf894fc2f7d2688bd4c4ad88c891a2e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 26 Nov 2016 19:54:14 +1300 Subject: Implement Maestro protocol decoder --- setup/default.xml | 1 + src/org/traccar/protocol/MaestroProtocol.java | 47 +++++++++ .../traccar/protocol/MaestroProtocolDecoder.java | 107 +++++++++++++++++++++ .../protocol/MaestroProtocolDecoderTest.java | 30 ++++++ 4 files changed, 185 insertions(+) create mode 100644 src/org/traccar/protocol/MaestroProtocol.java create mode 100644 src/org/traccar/protocol/MaestroProtocolDecoder.java create mode 100644 test/org/traccar/protocol/MaestroProtocolDecoderTest.java (limited to 'setup/default.xml') diff --git a/setup/default.xml b/setup/default.xml index 869c077cf..7df352c4d 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -441,5 +441,6 @@ 5126 5127 5128 + 5129 diff --git a/src/org/traccar/protocol/MaestroProtocol.java b/src/org/traccar/protocol/MaestroProtocol.java new file mode 100644 index 000000000..5e0b69916 --- /dev/null +++ b/src/org/traccar/protocol/MaestroProtocol.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.jboss.netty.bootstrap.ServerBootstrap; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.handler.codec.frame.FixedLengthFrameDecoder; +import org.jboss.netty.handler.codec.string.StringDecoder; +import org.jboss.netty.handler.codec.string.StringEncoder; +import org.traccar.BaseProtocol; +import org.traccar.TrackerServer; + +import java.util.List; + +public class MaestroProtocol extends BaseProtocol { + + public MaestroProtocol() { + super("maestro"); + } + + @Override + public void initTrackerServers(List serverList) { + serverList.add(new TrackerServer(new ServerBootstrap(), getName()) { + @Override + protected void addSpecificHandlers(ChannelPipeline pipeline) { + pipeline.addLast("frameDecoder", new FixedLengthFrameDecoder(160)); + pipeline.addLast("stringEncoder", new StringEncoder()); + pipeline.addLast("stringDecoder", new StringDecoder()); + pipeline.addLast("objectDecoder", new MaestroProtocolDecoder(MaestroProtocol.this)); + } + }); + } + +} diff --git a/src/org/traccar/protocol/MaestroProtocolDecoder.java b/src/org/traccar/protocol/MaestroProtocolDecoder.java new file mode 100644 index 000000000..06ec2473d --- /dev/null +++ b/src/org/traccar/protocol/MaestroProtocolDecoder.java @@ -0,0 +1,107 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.jboss.netty.channel.Channel; +import org.traccar.BaseProtocolDecoder; +import org.traccar.DeviceSession; +import org.traccar.helper.DateBuilder; +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 MaestroProtocolDecoder extends BaseProtocolDecoder { + + public MaestroProtocolDecoder(MaestroProtocol protocol) { + super(protocol); + } + + private static final Pattern PATTERN = new PatternBuilder() + .text("@") + .number("(d+),") // imei + .number("d+,") // index + .expression("[^,]+,") // profile + .expression("([01]),") // validity + .number("(d+.d+),") // battery + .number("(d+),") // gsm + .expression("([01]),") // starter + .expression("([01]),") // ignition + .number("(dd)/(dd)/(dd),") // date + .number("(dd):(dd):(dd),") // time + .number("(-?d+.d+),") // longitude + .number("(-?d+.d+),") // latitude + .number("(d+.?d*),") // altitude + .number("(d+.?d*),") // speed + .number("(d+.?d*),") // course + .number("(d+),") // satellites + .number("(d+.?d*),") // hdop + .number("(d+.?d*)") // odometer + .number(",(d+)").optional() // adc + .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; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(); + position.setProtocol(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + position.setValid(parser.nextInt() == 1); + + position.set(Position.KEY_BATTERY, parser.nextDouble()); + position.set(Position.KEY_GSM, parser.nextInt()); + position.set(Position.KEY_CHARGE, parser.nextInt() == 1); + position.set(Position.KEY_IGNITION, parser.nextInt() == 1); + + DateBuilder dateBuilder = new DateBuilder() + .setDate(parser.nextInt(), parser.nextInt(), parser.nextInt()) + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + position.setLatitude(parser.nextDouble()); + position.setLongitude(parser.nextDouble()); + position.setAltitude(parser.nextDouble()); + position.setSpeed(UnitsConverter.knotsFromMph(parser.nextDouble())); + position.setCourse(parser.nextDouble()); + + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_HDOP, parser.nextDouble()); + position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1609.34); + + if (parser.hasNext()) { + position.set(Position.PREFIX_ADC + 1, parser.nextInt()); + } + + return position; + } + +} diff --git a/test/org/traccar/protocol/MaestroProtocolDecoderTest.java b/test/org/traccar/protocol/MaestroProtocolDecoderTest.java new file mode 100644 index 000000000..b480ad9b2 --- /dev/null +++ b/test/org/traccar/protocol/MaestroProtocolDecoderTest.java @@ -0,0 +1,30 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class MaestroProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + MaestroProtocolDecoder decoder = new MaestroProtocolDecoder(new MaestroProtocol()); + + 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")); + + verifyPosition(decoder, text( + "@353893040202807,705,UPV-02,1,13.4,18,0,0,16/09/11,11:43:30,0.352808,32.647990,1211.0,0.000000,80.96,11,0.8,0.000,0!\0")); + + verifyPosition(decoder, text( + "@353893040202807,601,UPV-02,0,13.4,10,0,0,16/11/04,17:21:14,0.352793,32.647927,0,0,0,0,99,0.000,0!\0")); + + verifyPosition(decoder, text( + "@123451234512345,531,M2MGTW,1,12.5,30,0,0,11/10/10,09:09:09,22.222222,114.141414,45.6,0.0,160.0,8,1,20!")); + + verifyPosition(decoder, text( + "@123451234512345,702,M2MGTW,1,14.7,30,0,1,11/10/10,09:09:09,22.222222,114.141414,45.6,25.12,160.0,8,1,25!")); + + } + +} -- cgit v1.2.3 From d5ec75ecd3697e37782c9dd53998c889d5b9ef4d Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Wed, 30 Nov 2016 09:58:48 +0500 Subject: Add API to get positions by Id --- setup/default.xml | 4 ++++ src/org/traccar/api/resource/PositionResource.java | 16 +++++++++++++--- src/org/traccar/database/DataManager.java | 6 ++++++ 3 files changed, 23 insertions(+), 3 deletions(-) (limited to 'setup/default.xml') diff --git a/setup/default.xml b/setup/default.xml index 7df352c4d..5c6f8fe90 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -171,6 +171,10 @@ SELECT * FROM positions WHERE deviceId = :deviceId AND fixTime BETWEEN :from AND :to ORDER BY fixTime + + SELECT * FROM positions WHERE id = :id + + INSERT INTO positions (deviceId, protocol, serverTime, deviceTime, fixTime, valid, latitude, longitude, altitude, speed, course, address, attributes) VALUES (:deviceId, :protocol, :now, :deviceTime, :fixTime, :valid, :latitude, :longitude, :altitude, :speed, :course, :address, :attributes) diff --git a/src/org/traccar/api/resource/PositionResource.java b/src/org/traccar/api/resource/PositionResource.java index c1cfc0b5c..4db73cfd2 100644 --- a/src/org/traccar/api/resource/PositionResource.java +++ b/src/org/traccar/api/resource/PositionResource.java @@ -32,7 +32,9 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.sql.SQLException; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; @Path("positions") @Consumes(MediaType.APPLICATION_JSON) @@ -46,9 +48,18 @@ public class PositionResource extends BaseResource { @GET @Produces(MediaType.APPLICATION_JSON) public Collection getJson( - @QueryParam("deviceId") long deviceId, @QueryParam("from") String from, @QueryParam("to") String to) + @QueryParam("deviceId") long deviceId, @QueryParam("positionId") List positionIds, + @QueryParam("from") String from, @QueryParam("to") String to) throws SQLException { - if (deviceId == 0) { + if (!positionIds.isEmpty()) { + ArrayList positions = new ArrayList<>(); + for (Long positionId : positionIds) { + Position position = Context.getDataManager().getPosition(positionId); + Context.getPermissionsManager().checkDevice(getUserId(), position.getDeviceId()); + positions.add(position); + } + return positions; + } else if (deviceId == 0) { return Context.getDeviceManager().getInitialState(getUserId()); } else { Context.getPermissionsManager().checkDevice(getUserId(), deviceId); @@ -81,5 +92,4 @@ public class PositionResource extends BaseResource { deviceId, DateUtil.parseDate(from), DateUtil.parseDate(to))); return Response.ok(gpx.build()).header(HttpHeaders.CONTENT_DISPOSITION, CONTENT_DISPOSITION_VALUE_GPX).build(); } - } diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java index afa8b1677..8be53ad7b 100644 --- a/src/org/traccar/database/DataManager.java +++ b/src/org/traccar/database/DataManager.java @@ -280,6 +280,12 @@ public class DataManager { .executeQuery(Position.class); } + public Position getPosition(long positionId) throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectPosition")) + .setLong("id", positionId) + .executeQuerySingle(Position.class); + } + public void addPosition(Position position) throws SQLException { position.setId(QueryBuilder.create(dataSource, getQuery("database.insertPosition"), true) .setDate("now", new Date()) -- cgit v1.2.3 From 6bfda86daaef7ce7b591f2fe1b33ab3b1d5ca2cd Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Sun, 4 Dec 2016 17:33:17 +0700 Subject: Use model instead of attributes to store Notification options --- schema/changelog-3.9.xml | 37 ++++++++++++++++++++++ schema/changelog-master.xml | 1 + setup/default.xml | 6 ++-- .../traccar/api/resource/NotificationResource.java | 2 +- src/org/traccar/database/NotificationManager.java | 27 +++++++++++++--- src/org/traccar/model/Notification.java | 21 ++++++++++++ 6 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 schema/changelog-3.9.xml (limited to 'setup/default.xml') diff --git a/schema/changelog-3.9.xml b/schema/changelog-3.9.xml new file mode 100644 index 000000000..93fa6123b --- /dev/null +++ b/schema/changelog-3.9.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + attributes = '{"web":"true"}' + + + + + attributes = '{"mail":"true"}' + + + + + + attributes = '{"web":"true","mail":"true"}' + + + + + + + + diff --git a/schema/changelog-master.xml b/schema/changelog-master.xml index 341714ca8..448015568 100644 --- a/schema/changelog-master.xml +++ b/schema/changelog-master.xml @@ -10,4 +10,5 @@ + diff --git a/setup/default.xml b/setup/default.xml index 5c6f8fe90..ad23d7bd3 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -264,14 +264,16 @@ - INSERT INTO notifications (userId, type, attributes) - VALUES (:userId, :type, :attributes) + INSERT INTO notifications (userId, type, web, mail, attributes) + VALUES (:userId, :type, :web, :mail, :attributes) UPDATE notifications SET userId = :userId, type = :type, + web = :web, + mail = :mail, attributes = :attributes WHERE id = :id diff --git a/src/org/traccar/api/resource/NotificationResource.java b/src/org/traccar/api/resource/NotificationResource.java index 6c9725f37..03f7e4ba0 100644 --- a/src/org/traccar/api/resource/NotificationResource.java +++ b/src/org/traccar/api/resource/NotificationResource.java @@ -49,7 +49,7 @@ public class NotificationResource extends BaseResource { userId = getUserId(); } Context.getPermissionsManager().checkUser(getUserId(), userId); - return Context.getNotificationManager().getUserNotifications(userId); + return Context.getNotificationManager().getAllUserNotifications(userId); } @POST diff --git a/src/org/traccar/database/NotificationManager.java b/src/org/traccar/database/NotificationManager.java index 7e79e289f..caf1091cc 100644 --- a/src/org/traccar/database/NotificationManager.java +++ b/src/org/traccar/database/NotificationManager.java @@ -59,10 +59,10 @@ public class NotificationManager { && Context.getGeofenceManager().checkGeofence(userId, event.getGeofenceId())) { Notification notification = getUserNotificationByType(userId, event.getType()); if (notification != null) { - if (notification.getAttributes().containsKey("web")) { + if (notification.getWeb()) { Context.getConnectionManager().updateEvent(userId, event, position); } - if (notification.getAttributes().containsKey("mail")) { + if (notification.getMail()) { NotificationMail.sendMailAsync(userId, event, position); } } @@ -130,8 +130,11 @@ public class NotificationManager { public void updateNotification(Notification notification) { Notification cachedNotification = getUserNotificationByType(notification.getUserId(), notification.getType()); if (cachedNotification != null) { - if (!cachedNotification.getAttributes().equals(notification.getAttributes())) { - if (notification.getAttributes().isEmpty()) { + if (cachedNotification.getWeb() != notification.getWeb() + || cachedNotification.getMail() != notification.getMail() + || !cachedNotification.getAttributes().equals(notification.getAttributes())) { + if (!notification.getWeb() && !notification.getMail() + && notification.getAttributes().isEmpty()) { try { dataManager.removeNotification(cachedNotification); } catch (SQLException error) { @@ -146,6 +149,8 @@ public class NotificationManager { } else { notificationsLock.writeLock().lock(); try { + cachedNotification.setWeb(notification.getWeb()); + cachedNotification.setMail(notification.getMail()); cachedNotification.setAttributes(notification.getAttributes()); } finally { notificationsLock.writeLock().unlock(); @@ -159,7 +164,7 @@ public class NotificationManager { } else { notification.setId(cachedNotification.getId()); } - } else if (!notification.getAttributes().isEmpty()) { + } else if (notification.getWeb() || notification.getMail() || !notification.getAttributes().isEmpty()) { try { dataManager.addNotification(notification); } catch (SQLException error) { @@ -193,4 +198,16 @@ public class NotificationManager { return notifications; } + public Collection getAllUserNotifications(long userId) { + Map notifications = new HashMap<>(); + for (Notification notification : getAllNotifications()) { + notification.setUserId(userId); + notifications.put(notification.getType(), notification); + } + for (Notification notification : getUserNotifications(userId)) { + notifications.put(notification.getType(), notification); + } + return notifications.values(); + } + } diff --git a/src/org/traccar/model/Notification.java b/src/org/traccar/model/Notification.java index 64e1ac60c..3f08c0a39 100644 --- a/src/org/traccar/model/Notification.java +++ b/src/org/traccar/model/Notification.java @@ -37,4 +37,25 @@ public class Notification extends Extensible { this.type = type; } + private boolean web; + + public boolean getWeb() { + return web; + } + + public void setWeb(boolean web) { + this.web = web; + } + + private boolean mail; + + public boolean getMail() { + return mail; + } + + public void setMail(boolean mail) { + this.mail = mail; + } + + } -- cgit v1.2.3