diff options
Diffstat (limited to 'src/org/traccar/database')
-rw-r--r-- | src/org/traccar/database/ConnectionManager.java | 72 | ||||
-rw-r--r-- | src/org/traccar/database/DataManager.java | 133 | ||||
-rw-r--r-- | src/org/traccar/database/DeviceManager.java | 261 | ||||
-rw-r--r-- | src/org/traccar/database/GeofenceManager.java | 4 | ||||
-rw-r--r-- | src/org/traccar/database/IdentityManager.java | 3 | ||||
-rw-r--r-- | src/org/traccar/database/PermissionsManager.java | 2 | ||||
-rw-r--r-- | src/org/traccar/database/QueryBuilder.java | 12 |
7 files changed, 301 insertions, 186 deletions
diff --git a/src/org/traccar/database/ConnectionManager.java b/src/org/traccar/database/ConnectionManager.java index 8796673b1..46ccab81e 100644 --- a/src/org/traccar/database/ConnectionManager.java +++ b/src/org/traccar/database/ConnectionManager.java @@ -28,12 +28,9 @@ import org.traccar.model.Position; import java.net.SocketAddress; import java.sql.SQLException; -import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -45,21 +42,11 @@ public class ConnectionManager { private final long deviceTimeout; private final Map<Long, ActiveDevice> activeDevices = new HashMap<>(); - private final Map<Long, Position> positions = new HashMap<>(); private final Map<Long, Set<UpdateListener>> listeners = new HashMap<>(); private final Map<Long, Timeout> timeouts = new HashMap<>(); - public ConnectionManager(DataManager dataManager) { + public ConnectionManager() { deviceTimeout = Context.getConfig().getLong("status.timeout", DEFAULT_TIMEOUT) * 1000; - if (dataManager != null) { - try { - for (Position position : dataManager.getLatestPositions()) { - positions.put(position.getDeviceId(), position); - } - } catch (SQLException error) { - Log.warning(error); - } - } } public void addActiveDevice(long deviceId, Protocol protocol, Channel channel, SocketAddress remoteAddress) { @@ -80,31 +67,28 @@ public class ConnectionManager { return activeDevices.get(deviceId); } - public synchronized void updateDevice(final long deviceId, String status, Date time) { + public void updateDevice(final long deviceId, String status, Date time) { Device device = Context.getIdentityManager().getDeviceById(deviceId); if (device == null) { return; } - if (status.equals(Device.STATUS_MOVING) || status.equals(Device.STATUS_STOPPED)) { - device.setMotion(status); - } else { - if (!status.equals(device.getStatus())) { - Event event = new Event(Event.TYPE_DEVICE_OFFLINE, deviceId); - if (status.equals(Device.STATUS_ONLINE)) { - event.setType(Event.TYPE_DEVICE_ONLINE); - } - if (Context.getNotificationManager() != null) { - Context.getNotificationManager().updateEvent(event, null); - } + if (!status.equals(device.getStatus())) { + Event event = new Event(Event.TYPE_DEVICE_OFFLINE, deviceId); + if (status.equals(Device.STATUS_ONLINE)) { + event.setType(Event.TYPE_DEVICE_ONLINE); } - device.setStatus(status); - - Timeout timeout = timeouts.remove(deviceId); - if (timeout != null) { - timeout.cancel(); + if (Context.getNotificationManager() != null) { + Context.getNotificationManager().updateEvent(event, null); } } + device.setStatus(status); + + Timeout timeout = timeouts.remove(deviceId); + if (timeout != null) { + timeout.cancel(); + } + if (time != null) { device.setLastUpdate(time); @@ -122,12 +106,16 @@ public class ConnectionManager { } try { - Context.getDataManager().updateDeviceStatus(device); + Context.getDeviceManager().updateDeviceStatus(device); } catch (SQLException error) { Log.warning(error); } - for (long userId : Context.getPermissionsManager().getDeviceUsers(deviceId)) { + updateDevice(device); + } + + 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); @@ -138,7 +126,6 @@ public class ConnectionManager { public synchronized void updatePosition(Position position) { long deviceId = position.getDeviceId(); - positions.put(deviceId, position); for (long userId : Context.getPermissionsManager().getDeviceUsers(deviceId)) { if (listeners.containsKey(userId)) { @@ -157,23 +144,6 @@ public class ConnectionManager { } } - public Position getLastPosition(long deviceId) { - return positions.get(deviceId); - } - - public synchronized Collection<Position> getInitialState(long userId) { - - List<Position> result = new LinkedList<>(); - - for (long deviceId : Context.getPermissionsManager().getDevicePermissions(userId)) { - if (positions.containsKey(deviceId)) { - result.add(positions.get(deviceId)); - } - } - - return result; - } - public interface UpdateListener { void onUpdateDevice(Device device); void onUpdatePosition(Position position); diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java index bdd2e9adf..e5a245568 100644 --- a/src/org/traccar/database/DataManager.java +++ b/src/org/traccar/database/DataManager.java @@ -62,9 +62,9 @@ import org.traccar.model.GeofencePermission; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; -public class DataManager implements IdentityManager { +public class DataManager { - private static final long DEFAULT_REFRESH_DELAY = 300; + public static final long DEFAULT_REFRESH_DELAY = 300; private final Config config; @@ -72,11 +72,6 @@ public class DataManager implements IdentityManager { private final long dataRefreshDelay; - private final ReadWriteLock devicesLock = new ReentrantReadWriteLock(); - private final Map<Long, Device> devicesById = new HashMap<>(); - private final Map<String, Device> devicesByUniqueId = new HashMap<>(); - private long devicesLastUpdate; - private final ReadWriteLock groupsLock = new ReentrantReadWriteLock(); private final Map<Long, Group> groupsById = new HashMap<>(); private long groupsLastUpdate; @@ -136,85 +131,6 @@ public class DataManager implements IdentityManager { } } - private void updateDeviceCache(boolean force) throws SQLException { - boolean needWrite; - devicesLock.readLock().lock(); - try { - needWrite = force || System.currentTimeMillis() - devicesLastUpdate > dataRefreshDelay; - } finally { - devicesLock.readLock().unlock(); - } - - if (needWrite) { - devicesLock.writeLock().lock(); - try { - if (force || System.currentTimeMillis() - devicesLastUpdate > dataRefreshDelay) { - devicesById.clear(); - devicesByUniqueId.clear(); - ConnectionManager connectionManager = Context.getConnectionManager(); - GeofenceManager geofenceManager = Context.getGeofenceManager(); - for (Device device : getAllDevices()) { - devicesById.put(device.getId(), device); - devicesByUniqueId.put(device.getUniqueId(), device); - if (connectionManager != null && geofenceManager != null) { - Position lastPosition = connectionManager.getLastPosition(device.getId()); - if (lastPosition != null) { - device.setGeofenceIds(geofenceManager.getCurrentDeviceGeofences(lastPosition)); - } - } - } - devicesLastUpdate = System.currentTimeMillis(); - } - } finally { - devicesLock.writeLock().unlock(); - } - } - } - - @Override - public Device getDeviceById(long id) { - boolean forceUpdate; - devicesLock.readLock().lock(); - try { - forceUpdate = !devicesById.containsKey(id); - } finally { - devicesLock.readLock().unlock(); - } - - try { - updateDeviceCache(forceUpdate); - } catch (SQLException e) { - Log.warning(e); - } - - devicesLock.readLock().lock(); - try { - return devicesById.get(id); - } finally { - devicesLock.readLock().unlock(); - } - } - - @Override - public Device getDeviceByUniqueId(String uniqueId) throws SQLException { - boolean forceUpdate; - devicesLock.readLock().lock(); - try { - forceUpdate = !devicesByUniqueId.containsKey(uniqueId) && !config.getBoolean("database.ignoreUnknown"); - } finally { - devicesLock.readLock().unlock(); - } - - updateDeviceCache(forceUpdate); - - devicesLock.readLock().lock(); - try { - return devicesByUniqueId.get(uniqueId); - } finally { - devicesLock.readLock().unlock(); - } - } - private void updateGroupCache(boolean force) throws SQLException { boolean needWrite; groupsLock.readLock().lock(); @@ -347,72 +263,33 @@ public class DataManager implements IdentityManager { .executeQuery(GroupPermission.class); } - private Collection<Device> getAllDevices() throws SQLException { + public Collection<Device> getAllDevices() throws SQLException { return QueryBuilder.create(dataSource, getQuery("database.selectDevicesAll")) .executeQuery(Device.class); } - public Collection<Device> getAllDevicesCached() { - boolean forceUpdate; - devicesLock.readLock().lock(); - try { - forceUpdate = devicesById.isEmpty(); - } finally { - devicesLock.readLock().unlock(); - } - - try { - updateDeviceCache(forceUpdate); - } catch (SQLException e) { - Log.warning(e); - } - - devicesLock.readLock().lock(); - try { - return devicesById.values(); - } finally { - devicesLock.readLock().unlock(); - } - } - - public Collection<Device> getDevices(long userId) throws SQLException { - Collection<Device> devices = new ArrayList<>(); - for (long id : Context.getPermissionsManager().getDevicePermissions(userId)) { - devices.add(getDeviceById(id)); - } - return devices; - } - public void addDevice(Device device) throws SQLException { device.setId(QueryBuilder.create(dataSource, getQuery("database.insertDevice"), true) .setObject(device) .executeUpdate()); - updateDeviceCache(true); } public void updateDevice(Device device) throws SQLException { QueryBuilder.create(dataSource, getQuery("database.updateDevice")) .setObject(device) .executeUpdate(); - updateDeviceCache(true); } public void updateDeviceStatus(Device device) throws SQLException { QueryBuilder.create(dataSource, getQuery("database.updateDeviceStatus")) .setObject(device) .executeUpdate(); - if (devicesById.containsKey(device.getId())) { - Device cachedDevice = devicesById.get(device.getId()); - cachedDevice.setStatus(device.getStatus()); - cachedDevice.setMotion(device.getMotion()); - } } public void removeDevice(long deviceId) throws SQLException { QueryBuilder.create(dataSource, getQuery("database.deleteDevice")) .setLong("id", deviceId) .executeUpdate(); - updateDeviceCache(true); } public void linkDevice(long userId, long deviceId) throws SQLException { @@ -514,10 +391,6 @@ public class DataManager implements IdentityManager { .setDate("now", new Date()) .setObject(position) .executeUpdate(); - if (devicesById.containsKey(position.getDeviceId())) { - Device cachedDevice = devicesById.get(position.getDeviceId()); - cachedDevice.setPositionId(position.getId()); - } } public Collection<Position> getLatestPositions() throws SQLException { diff --git a/src/org/traccar/database/DeviceManager.java b/src/org/traccar/database/DeviceManager.java new file mode 100644 index 000000000..70df1cc1a --- /dev/null +++ b/src/org/traccar/database/DeviceManager.java @@ -0,0 +1,261 @@ +package org.traccar.database; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.traccar.Config; +import org.traccar.Context; +import org.traccar.helper.Log; +import org.traccar.model.Device; +import org.traccar.model.Position; + +public class DeviceManager implements IdentityManager { + + private final Config config; + private final DataManager dataManager; + private final long dataRefreshDelay; + + private final ReadWriteLock devicesLock = new ReentrantReadWriteLock(); + private final Map<Long, Device> devicesById = new HashMap<>(); + private final Map<String, Device> devicesByUniqueId = new HashMap<>(); + private long devicesLastUpdate; + + private final Map<Long, Position> positions = new ConcurrentHashMap<>(); + + public DeviceManager(DataManager dataManager) { + this.dataManager = dataManager; + this.config = Context.getConfig(); + dataRefreshDelay = config.getLong("database.refreshDelay", DataManager.DEFAULT_REFRESH_DELAY) * 1000; + if (dataManager != null) { + try { + for (Position position : dataManager.getLatestPositions()) { + positions.put(position.getDeviceId(), position); + } + } catch (SQLException error) { + Log.warning(error); + } + } + } + + private void updateDeviceCache(boolean force) throws SQLException { + boolean needWrite; + devicesLock.readLock().lock(); + try { + needWrite = force || System.currentTimeMillis() - devicesLastUpdate > dataRefreshDelay; + } finally { + devicesLock.readLock().unlock(); + } + + if (needWrite) { + devicesLock.writeLock().lock(); + try { + if (force || System.currentTimeMillis() - devicesLastUpdate > dataRefreshDelay) { + devicesById.clear(); + devicesByUniqueId.clear(); + GeofenceManager geofenceManager = Context.getGeofenceManager(); + for (Device device : dataManager.getAllDevices()) { + devicesById.put(device.getId(), device); + devicesByUniqueId.put(device.getUniqueId(), device); + if (geofenceManager != null) { + Position lastPosition = getLastPosition(device.getId()); + if (lastPosition != null) { + device.setGeofenceIds(geofenceManager.getCurrentDeviceGeofences(lastPosition)); + } + } + } + devicesLastUpdate = System.currentTimeMillis(); + } + } finally { + devicesLock.writeLock().unlock(); + } + } + } + + @Override + public Device getDeviceById(long id) { + boolean forceUpdate; + devicesLock.readLock().lock(); + try { + forceUpdate = !devicesById.containsKey(id); + } finally { + devicesLock.readLock().unlock(); + } + + try { + updateDeviceCache(forceUpdate); + } catch (SQLException e) { + Log.warning(e); + } + + devicesLock.readLock().lock(); + try { + return devicesById.get(id); + } finally { + devicesLock.readLock().unlock(); + } + } + + @Override + public Device getDeviceByUniqueId(String uniqueId) throws SQLException { + boolean forceUpdate; + devicesLock.readLock().lock(); + try { + forceUpdate = !devicesByUniqueId.containsKey(uniqueId) && !config.getBoolean("database.ignoreUnknown"); + } finally { + devicesLock.readLock().unlock(); + } + + updateDeviceCache(forceUpdate); + + devicesLock.readLock().lock(); + try { + return devicesByUniqueId.get(uniqueId); + } finally { + devicesLock.readLock().unlock(); + } + } + + public Collection<Device> getAllDevices() { + boolean forceUpdate; + devicesLock.readLock().lock(); + try { + forceUpdate = devicesById.isEmpty(); + } finally { + devicesLock.readLock().unlock(); + } + + try { + updateDeviceCache(forceUpdate); + } catch (SQLException e) { + Log.warning(e); + } + + devicesLock.readLock().lock(); + try { + return devicesById.values(); + } finally { + devicesLock.readLock().unlock(); + } + } + + public Collection<Device> getDevices(long userId) throws SQLException { + Collection<Device> devices = new ArrayList<>(); + devicesLock.readLock().lock(); + try { + for (long id : Context.getPermissionsManager().getDevicePermissions(userId)) { + devices.add(devicesById.get(id)); + } + } finally { + devicesLock.readLock().unlock(); + } + return devices; + } + + public void addDevice(Device device) throws SQLException { + dataManager.addDevice(device); + + devicesLock.writeLock().lock(); + try { + devicesById.put(device.getId(), device); + devicesByUniqueId.put(device.getUniqueId(), device); + } finally { + devicesLock.writeLock().unlock(); + } + } + + public void updateDevice(Device device) throws SQLException { + dataManager.updateDevice(device); + + devicesLock.writeLock().lock(); + try { + devicesById.put(device.getId(), device); + devicesByUniqueId.put(device.getUniqueId(), device); + } finally { + devicesLock.writeLock().unlock(); + } + } + + public void updateDeviceStatus(Device device) throws SQLException { + dataManager.updateDeviceStatus(device); + + devicesLock.writeLock().lock(); + try { + if (devicesById.containsKey(device.getId())) { + Device cachedDevice = devicesById.get(device.getId()); + cachedDevice.setStatus(device.getStatus()); + cachedDevice.setMotion(device.getMotion()); + } + } finally { + devicesLock.writeLock().unlock(); + } + } + + public void removeDevice(long deviceId) throws SQLException { + dataManager.removeDevice(deviceId); + + devicesLock.writeLock().lock(); + try { + if (devicesById.containsKey(deviceId)) { + String deviceUniqueId = devicesById.get(deviceId).getUniqueId(); + devicesById.remove(deviceId); + devicesByUniqueId.remove(deviceUniqueId); + } + } finally { + devicesLock.writeLock().unlock(); + } + + positions.remove(deviceId); + } + + public void updateLatestPosition(Position position) throws SQLException { + + Position lastPosition = getLastPosition(position.getDeviceId()); + if (lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) > 0) { + + dataManager.updateLatestPosition(position); + + devicesLock.writeLock().lock(); + try { + if (devicesById.containsKey(position.getDeviceId())) { + devicesById.get(position.getDeviceId()).setPositionId(position.getId()); + } + } finally { + devicesLock.writeLock().unlock(); + } + + 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().getDevicePermissions(userId)) { + if (positions.containsKey(deviceId)) { + result.add(positions.get(deviceId)); + } + } + } + + return result; + } +} diff --git a/src/org/traccar/database/GeofenceManager.java b/src/org/traccar/database/GeofenceManager.java index c35e19e9a..dc31172b9 100644 --- a/src/org/traccar/database/GeofenceManager.java +++ b/src/org/traccar/database/GeofenceManager.java @@ -173,7 +173,7 @@ public class GeofenceManager { .add(deviceGeofence.getGeofenceId()); } - for (Device device : dataManager.getAllDevicesCached()) { + for (Device device : Context.getDeviceManager().getAllDevices()) { long groupId = device.getGroupId(); while (groupId != 0) { getDeviceGeofences(deviceGeofencesWithGroups, @@ -190,7 +190,7 @@ public class GeofenceManager { } else { deviceGeofenceIds.clear(); } - Position lastPosition = Context.getConnectionManager().getLastPosition(device.getId()); + Position lastPosition = Context.getIdentityManager().getLastPosition(device.getId()); if (lastPosition != null && deviceGeofencesWithGroups.containsKey(device.getId())) { for (long geofenceId : deviceGeofencesWithGroups.get(device.getId())) { Geofence geofence = getGeofence(geofenceId); diff --git a/src/org/traccar/database/IdentityManager.java b/src/org/traccar/database/IdentityManager.java index 8bdce09a3..8c0de8b38 100644 --- a/src/org/traccar/database/IdentityManager.java +++ b/src/org/traccar/database/IdentityManager.java @@ -16,6 +16,7 @@ package org.traccar.database; import org.traccar.model.Device; +import org.traccar.model.Position; public interface IdentityManager { @@ -23,4 +24,6 @@ public interface IdentityManager { Device getDeviceByUniqueId(String uniqueId) throws Exception; + Position getLastPosition(long deviceId); + } diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java index b6dd2e2a9..5a15375b4 100644 --- a/src/org/traccar/database/PermissionsManager.java +++ b/src/org/traccar/database/PermissionsManager.java @@ -78,7 +78,7 @@ public class PermissionsManager { users.put(user.getId(), user); } - GroupTree groupTree = new GroupTree(dataManager.getAllGroups(), dataManager.getAllDevicesCached()); + GroupTree groupTree = new GroupTree(dataManager.getAllGroups(), Context.getDeviceManager().getAllDevices()); for (GroupPermission permission : dataManager.getGroupPermissions()) { Set<Long> userGroupPermissions = getGroupPermissions(permission.getUserId()); Set<Long> userDevicePermissions = getDevicePermissions(permission.getUserId()); diff --git a/src/org/traccar/database/QueryBuilder.java b/src/org/traccar/database/QueryBuilder.java index 73569ac2a..1a83daab9 100644 --- a/src/org/traccar/database/QueryBuilder.java +++ b/src/org/traccar/database/QueryBuilder.java @@ -173,9 +173,17 @@ public final class QueryBuilder { } public QueryBuilder setLong(String name, long value) throws SQLException { + return setLong(name, value, false); + } + + public QueryBuilder setLong(String name, long value, boolean nullIfZero) throws SQLException { for (int i : indexes(name)) { try { - statement.setLong(i, value); + if (value == 0 && nullIfZero) { + statement.setNull(i, Types.INTEGER); + } else { + statement.setLong(i, value); + } } catch (SQLException error) { statement.close(); connection.close(); @@ -245,7 +253,7 @@ public final class QueryBuilder { } 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)); + 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)) { |