aboutsummaryrefslogtreecommitdiff
path: root/src/org/traccar/database
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/traccar/database')
-rw-r--r--src/org/traccar/database/ConnectionManager.java72
-rw-r--r--src/org/traccar/database/DataManager.java133
-rw-r--r--src/org/traccar/database/DeviceManager.java261
-rw-r--r--src/org/traccar/database/GeofenceManager.java4
-rw-r--r--src/org/traccar/database/IdentityManager.java3
-rw-r--r--src/org/traccar/database/PermissionsManager.java2
-rw-r--r--src/org/traccar/database/QueryBuilder.java12
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)) {