aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAnton Tananaev <anton@traccar.org>2022-06-04 06:33:02 -0700
committerAnton Tananaev <anton@traccar.org>2022-06-04 06:33:02 -0700
commitec76482c15094a7e04964c67d3011a7e8e1ad6a9 (patch)
tree3ef0d23e1b9f4ba7ef02f68b08db33f3db1972ab /src
parent4030d3207c157a3fcee2653c18440898b6b2a2e6 (diff)
downloadtrackermap-server-ec76482c15094a7e04964c67d3011a7e8e1ad6a9.tar.gz
trackermap-server-ec76482c15094a7e04964c67d3011a7e8e1ad6a9.tar.bz2
trackermap-server-ec76482c15094a7e04964c67d3011a7e8e1ad6a9.zip
Refactor commands manager
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/traccar/BaseProtocolDecoder.java19
-rw-r--r--src/main/java/org/traccar/Context.java12
-rw-r--r--src/main/java/org/traccar/MainModule.java6
-rw-r--r--src/main/java/org/traccar/api/resource/CommandResource.java104
-rw-r--r--src/main/java/org/traccar/api/resource/PositionResource.java3
-rw-r--r--src/main/java/org/traccar/api/resource/ReportResource.java21
-rw-r--r--src/main/java/org/traccar/api/security/PermissionsService.java12
-rw-r--r--src/main/java/org/traccar/database/CommandsManager.java149
-rw-r--r--src/main/java/org/traccar/database/DataManager.java13
-rw-r--r--src/main/java/org/traccar/database/PermissionsManager.java31
-rw-r--r--src/main/java/org/traccar/model/Server.java6
-rw-r--r--src/main/java/org/traccar/model/User.java8
-rw-r--r--src/main/java/org/traccar/model/UserRestrictions.java23
-rw-r--r--src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java9
-rw-r--r--src/main/java/org/traccar/storage/DatabaseStorage.java16
-rw-r--r--src/main/java/org/traccar/storage/query/Condition.java16
-rw-r--r--src/test/java/org/traccar/BaseTest.java2
17 files changed, 241 insertions, 209 deletions
diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java
index 71ef686fa..5b3f129de 100644
--- a/src/main/java/org/traccar/BaseProtocolDecoder.java
+++ b/src/main/java/org/traccar/BaseProtocolDecoder.java
@@ -15,7 +15,6 @@
*/
package org.traccar;
-import com.google.inject.Inject;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.traccar.config.Config;
@@ -32,6 +31,7 @@ import org.traccar.session.ConnectionManager;
import org.traccar.session.DeviceSession;
import org.traccar.storage.StorageException;
+import javax.inject.Inject;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Collection;
@@ -51,6 +51,7 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
private ConnectionManager connectionManager;
private StatisticsManager statisticsManager;
private MediaManager mediaManager;
+ private CommandsManager commandsManager;
public BaseProtocolDecoder(Protocol protocol) {
this.protocol = protocol;
@@ -96,6 +97,15 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
this.mediaManager = mediaManager;
}
+ @Inject
+ public void setCommandsManager(CommandsManager commandsManager) {
+ this.commandsManager = commandsManager;
+ }
+
+ public CommandsManager getCommandsManager() {
+ return commandsManager;
+ }
+
public String writeMediaFile(String uniqueId, ByteBuf buf, String extension) {
return mediaManager.writeFile(uniqueId, buf, extension);
}
@@ -204,11 +214,8 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
}
protected void sendQueuedCommands(Channel channel, SocketAddress remoteAddress, long deviceId) {
- CommandsManager commandsManager = Context.getCommandsManager();
- if (commandsManager != null) {
- for (Command command : commandsManager.readQueuedCommands(deviceId)) {
- protocol.sendDataCommand(channel, remoteAddress, command);
- }
+ for (Command command : commandsManager.readQueuedCommands(deviceId)) {
+ protocol.sendDataCommand(channel, remoteAddress, command);
}
}
diff --git a/src/main/java/org/traccar/Context.java b/src/main/java/org/traccar/Context.java
index 4eab36a89..6ee8344ce 100644
--- a/src/main/java/org/traccar/Context.java
+++ b/src/main/java/org/traccar/Context.java
@@ -25,7 +25,6 @@ import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.database.BaseObjectManager;
import org.traccar.database.CalendarManager;
-import org.traccar.database.CommandsManager;
import org.traccar.session.ConnectionManager;
import org.traccar.database.DataManager;
import org.traccar.database.DeviceManager;
@@ -45,7 +44,6 @@ import org.traccar.helper.Log;
import org.traccar.helper.SanitizerModule;
import org.traccar.model.BaseModel;
import org.traccar.model.Calendar;
-import org.traccar.model.Command;
import org.traccar.model.Device;
import org.traccar.model.Driver;
import org.traccar.model.Geofence;
@@ -217,12 +215,6 @@ public final class Context {
return driversManager;
}
- private static CommandsManager commandsManager;
-
- public static CommandsManager getCommandsManager() {
- return commandsManager;
- }
-
private static MaintenancesManager maintenancesManager;
public static MaintenancesManager getMaintenancesManager() {
@@ -337,8 +329,6 @@ public final class Context {
driversManager = new DriversManager(dataManager);
- commandsManager = new CommandsManager(dataManager, config.getBoolean(Keys.COMMANDS_QUEUEING));
-
orderManager = new OrderManager(dataManager);
}
@@ -392,8 +382,6 @@ public final class Context {
return (BaseObjectManager<T>) geofenceManager;
} else if (clazz.equals(Driver.class)) {
return (BaseObjectManager<T>) driversManager;
- } else if (clazz.equals(Command.class)) {
- return (BaseObjectManager<T>) commandsManager;
} else if (clazz.equals(Maintenance.class)) {
return (BaseObjectManager<T>) maintenancesManager;
} else if (clazz.equals(Notification.class)) {
diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java
index f46312221..7b46656b3 100644
--- a/src/main/java/org/traccar/MainModule.java
+++ b/src/main/java/org/traccar/MainModule.java
@@ -60,6 +60,7 @@ import org.traccar.handler.GeocoderHandler;
import org.traccar.handler.GeolocationHandler;
import org.traccar.handler.SpeedLimitHandler;
import org.traccar.reports.model.TripsConfig;
+import org.traccar.sms.SmsManager;
import org.traccar.speedlimit.OverpassSpeedLimitProvider;
import org.traccar.speedlimit.SpeedLimitProvider;
import org.traccar.storage.Storage;
@@ -134,6 +135,11 @@ public class MainModule extends AbstractModule {
return Context.getMaintenancesManager();
}
+ @Provides
+ public static SmsManager provideSmsManager() {
+ return Context.getSmsManager();
+ }
+
@Singleton
@Provides
public static Geocoder provideGeocoder(Config config) {
diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java
index a31345246..17bb150f6 100644
--- a/src/main/java/org/traccar/api/resource/CommandResource.java
+++ b/src/main/java/org/traccar/api/resource/CommandResource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2016 Gabor Somogyi (gabor.g.somogyi@gmail.com)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
@@ -17,16 +17,23 @@
*/
package org.traccar.api.resource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.BaseProtocol;
import org.traccar.Context;
import org.traccar.api.ExtendedObjectResource;
import org.traccar.database.CommandsManager;
import org.traccar.model.Command;
+import org.traccar.model.Device;
+import org.traccar.model.Position;
import org.traccar.model.Typed;
+import org.traccar.model.UserRestrictions;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
+import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
@@ -35,40 +42,61 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
@Path("commands")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class CommandResource extends ExtendedObjectResource<Command> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(CommandResource.class);
+
+ @Inject
+ private CommandsManager commandsManager;
+
public CommandResource() {
super(Command.class);
}
+ private BaseProtocol getDeviceProtocol(long deviceId) throws StorageException {
+ Position position = storage.getObject(Position.class, new Request(
+ new Columns.All(), new Condition.LatestPositions(deviceId)));
+ if (position != null) {
+ return Context.getServerManager().getProtocol(position.getProtocol());
+ } else {
+ return null;
+ }
+ }
+
@GET
@Path("send")
- public Collection<Command> get(@QueryParam("deviceId") long deviceId) {
- Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
- CommandsManager commandsManager = Context.getCommandsManager();
- Set<Long> result = new HashSet<>(commandsManager.getUserItems(getUserId()));
- result.retainAll(commandsManager.getSupportedCommands(deviceId));
- return commandsManager.getItems(result);
+ public Collection<Command> get(@QueryParam("deviceId") long deviceId) throws StorageException {
+ permissionsService.checkPermission(Device.class, getUserId(), deviceId);
+ BaseProtocol protocol = getDeviceProtocol(deviceId);
+ return get(false, 0, 0, deviceId).stream().filter(command -> {
+ String type = command.getType();
+ if (protocol != null) {
+ return command.getTextChannel() && protocol.getSupportedTextCommands().contains(type)
+ || !command.getTextChannel() && protocol.getSupportedDataCommands().contains(type);
+ } else {
+ return type.equals(Command.TYPE_CUSTOM);
+ }
+ }).collect(Collectors.toList());
}
@POST
@Path("send")
public Response send(Command entity) throws Exception {
- Context.getPermissionsManager().checkReadonly(getUserId());
- long deviceId = entity.getDeviceId();
- long id = entity.getId();
- Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
- if (id != 0) {
- Context.getPermissionsManager().checkPermission(Command.class, getUserId(), id);
- Context.getPermissionsManager().checkUserDeviceCommand(getUserId(), deviceId, id);
- } else {
- Context.getPermissionsManager().checkLimitCommands(getUserId());
- }
- if (!Context.getCommandsManager().sendCommand(entity)) {
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getReadonly);
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getLimitCommands);
+ permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId());
+ if (!commandsManager.sendCommand(entity)) {
return Response.accepted(entity).build();
}
return Response.ok(entity).build();
@@ -78,15 +106,33 @@ public class CommandResource extends ExtendedObjectResource<Command> {
@Path("types")
public Collection<Typed> get(
@QueryParam("deviceId") long deviceId,
- @QueryParam("protocol") String protocol,
- @QueryParam("textChannel") boolean textChannel) {
+ @QueryParam("textChannel") boolean textChannel) throws StorageException {
if (deviceId != 0) {
- Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
- return Context.getCommandsManager().getCommandTypes(deviceId, textChannel);
- } else if (protocol != null) {
- return Context.getCommandsManager().getCommandTypes(protocol, textChannel);
+ permissionsService.checkPermission(Device.class, getUserId(), deviceId);
+ BaseProtocol protocol = getDeviceProtocol(deviceId);
+ if (protocol != null) {
+ if (textChannel) {
+ return protocol.getSupportedTextCommands().stream().map(Typed::new).collect(Collectors.toList());
+ } else {
+ return protocol.getSupportedDataCommands().stream().map(Typed::new).collect(Collectors.toList());
+ }
+ } else {
+ return Collections.singletonList(new Typed(Command.TYPE_CUSTOM));
+ }
} else {
- return Context.getCommandsManager().getAllCommandTypes();
+ List<Typed> result = new ArrayList<>();
+ Field[] fields = Command.class.getDeclaredFields();
+ for (Field field : fields) {
+ if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("TYPE_")) {
+ try {
+ result.add(new Typed(field.get(null).toString()));
+ } catch (IllegalArgumentException | IllegalAccessException error) {
+ LOGGER.warn("Get command types error", error);
+ }
+ }
+ }
+ return result;
}
}
+
}
diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java
index 941417231..2618a04cb 100644
--- a/src/main/java/org/traccar/api/resource/PositionResource.java
+++ b/src/main/java/org/traccar/api/resource/PositionResource.java
@@ -18,6 +18,7 @@ package org.traccar.api.resource;
import org.traccar.Context;
import org.traccar.api.BaseResource;
import org.traccar.model.Position;
+import org.traccar.model.UserRestrictions;
import org.traccar.storage.StorageException;
import javax.ws.rs.Consumes;
@@ -55,7 +56,7 @@ public class PositionResource extends BaseResource {
} else {
Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
if (from != null && to != null) {
- permissionsService.checkReports(getUserId());
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return Context.getDataManager().getPositions(deviceId, from, to);
} else {
return Collections.singleton(Context.getDeviceManager().getLastPosition(deviceId));
diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java
index 901385d0d..06ccbe4fd 100644
--- a/src/main/java/org/traccar/api/resource/ReportResource.java
+++ b/src/main/java/org/traccar/api/resource/ReportResource.java
@@ -42,6 +42,7 @@ import org.traccar.api.BaseResource;
import org.traccar.helper.LogAction;
import org.traccar.model.Event;
import org.traccar.model.Position;
+import org.traccar.model.UserRestrictions;
import org.traccar.reports.Events;
import org.traccar.reports.Summary;
import org.traccar.reports.Trips;
@@ -99,7 +100,7 @@ public class ReportResource extends BaseResource {
public Collection<Position> getRoute(
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
- permissionsService.checkReports(getUserId());
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds);
return Route.getObjects(getUserId(), deviceIds, groupIds, from, to);
}
@@ -111,7 +112,7 @@ public class ReportResource extends BaseResource {
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail)
throws StorageException, IOException {
- permissionsService.checkReports(getUserId());
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds);
Route.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
@@ -124,7 +125,7 @@ public class ReportResource extends BaseResource {
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("type") final List<String> types,
@QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
- permissionsService.checkReports(getUserId());
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds);
return Events.getObjects(getUserId(), deviceIds, groupIds, types, from, to);
}
@@ -137,7 +138,7 @@ public class ReportResource extends BaseResource {
@QueryParam("type") final List<String> types,
@QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail)
throws StorageException, IOException {
- permissionsService.checkReports(getUserId());
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds);
Events.getExcel(stream, getUserId(), deviceIds, groupIds, types, from, to);
@@ -150,7 +151,7 @@ public class ReportResource extends BaseResource {
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("daily") boolean daily)
throws StorageException {
- permissionsService.checkReports(getUserId());
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds);
return Summary.getObjects(getUserId(), deviceIds, groupIds, from, to, daily);
}
@@ -163,7 +164,7 @@ public class ReportResource extends BaseResource {
@QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("daily") boolean daily,
@QueryParam("mail") boolean mail)
throws StorageException, IOException {
- permissionsService.checkReports(getUserId());
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds);
Summary.getExcel(stream, getUserId(), deviceIds, groupIds, from, to, daily);
@@ -176,7 +177,7 @@ public class ReportResource extends BaseResource {
public Collection<TripReport> getTrips(
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
- permissionsService.checkReports(getUserId());
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds);
return Trips.getObjects(getUserId(), deviceIds, groupIds, from, to);
}
@@ -188,7 +189,7 @@ public class ReportResource extends BaseResource {
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail)
throws StorageException, IOException {
- permissionsService.checkReports(getUserId());
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds);
Trips.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
@@ -201,7 +202,7 @@ public class ReportResource extends BaseResource {
public Collection<StopReport> getStops(
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException {
- permissionsService.checkReports(getUserId());
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds);
return Stops.getObjects(getUserId(), deviceIds, groupIds, from, to);
}
@@ -213,7 +214,7 @@ public class ReportResource extends BaseResource {
@QueryParam("deviceId") final List<Long> deviceIds, @QueryParam("groupId") final List<Long> groupIds,
@QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail)
throws StorageException, IOException {
- permissionsService.checkReports(getUserId());
+ permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports);
return executeReport(getUserId(), mail, stream -> {
LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds);
Stops.getExcel(stream, getUserId(), deviceIds, groupIds, from, to);
diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java
index 9daef355e..b4a375109 100644
--- a/src/main/java/org/traccar/api/security/PermissionsService.java
+++ b/src/main/java/org/traccar/api/security/PermissionsService.java
@@ -25,6 +25,7 @@ import org.traccar.model.ManagedUser;
import org.traccar.model.ScheduledModel;
import org.traccar.model.Server;
import org.traccar.model.User;
+import org.traccar.model.UserRestrictions;
import org.traccar.storage.Storage;
import org.traccar.storage.StorageException;
import org.traccar.storage.query.Columns;
@@ -71,10 +72,15 @@ public class PermissionsService {
}
}
- public void checkReports(long userId) throws StorageException, SecurityException {
+ public interface CheckRestrictionCallback {
+ boolean denied(UserRestrictions userRestrictions);
+ }
+
+ public void checkRestriction(
+ long userId, CheckRestrictionCallback callback) throws StorageException, SecurityException {
if (!getUser(userId).getAdministrator()
- && (getServer().getDisableReports() || getUser(userId).getDisableReports())) {
- throw new SecurityException("Reports are disabled");
+ && (callback.denied(getServer()) || callback.denied(getUser(userId)))) {
+ throw new SecurityException("Operation restricted");
}
}
diff --git a/src/main/java/org/traccar/database/CommandsManager.java b/src/main/java/org/traccar/database/CommandsManager.java
index 57ce0f9a4..d440755f7 100644
--- a/src/main/java/org/traccar/database/CommandsManager.java
+++ b/src/main/java/org/traccar/database/CommandsManager.java
@@ -16,66 +16,75 @@
*/
package org.traccar.database;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
+import org.traccar.BaseProtocol;
+import org.traccar.ServerManager;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import org.traccar.model.Command;
+import org.traccar.model.Device;
+import org.traccar.model.Position;
+import org.traccar.session.ConnectionManager;
+import org.traccar.session.DeviceSession;
+import org.traccar.sms.SmsManager;
+import org.traccar.storage.Storage;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
+
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.inject.Singleton;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.BaseProtocol;
-import org.traccar.Context;
-import org.traccar.model.Command;
-import org.traccar.model.Typed;
-import org.traccar.model.Position;
-import org.traccar.session.DeviceSession;
-
-public class CommandsManager extends ExtendedObjectManager<Command> {
+@Singleton
+public class CommandsManager {
- private static final Logger LOGGER = LoggerFactory.getLogger(CommandsManager.class);
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Map<Long, Queue<Command>> deviceQueues = new ConcurrentHashMap<>();
- private final boolean queueing;
+ private final Storage storage;
+ private final ServerManager serverManager;
+ private final SmsManager smsManager;
+ private final ConnectionManager connectionManager;
- public CommandsManager(DataManager dataManager, boolean queueing) {
- super(dataManager, Command.class);
- this.queueing = queueing;
- }
+ private final boolean queueing;
- public boolean checkDeviceCommand(long deviceId, long commandId) {
- return !getAllDeviceItems(deviceId).contains(commandId);
+ @Inject
+ public CommandsManager(
+ Storage storage, ServerManager serverManager, @Nullable SmsManager smsManager,
+ ConnectionManager connectionManager, Config config) {
+ this.storage = storage;
+ this.serverManager = serverManager;
+ this.smsManager = smsManager;
+ this.connectionManager = connectionManager;
+ queueing = config.getBoolean(Keys.COMMANDS_QUEUEING);
}
public boolean sendCommand(Command command) throws Exception {
long deviceId = command.getDeviceId();
- if (command.getId() != 0) {
- command = getById(command.getId()).clone();
- command.setDeviceId(deviceId);
- }
if (command.getTextChannel()) {
- Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId);
- String phone = Context.getIdentityManager().getById(deviceId).getPhone();
- if (lastPosition != null) {
- BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol());
- protocol.sendTextCommand(phone, command);
+ Device device = storage.getObject(Device.class, new Request(
+ new Columns.All(), new Condition.Equals("id", "id", deviceId)));
+ Position position = storage.getObject(Position.class, new Request(
+ new Columns.All(), new Condition.Equals("id", "id", device.getPositionId())));
+ if (position != null) {
+ BaseProtocol protocol = serverManager.getProtocol(position.getProtocol());
+ protocol.sendTextCommand(device.getPhone(), command);
} else if (command.getType().equals(Command.TYPE_CUSTOM)) {
- if (Context.getSmsManager() != null) {
- Context.getSmsManager().sendMessageSync(phone, command.getString(Command.KEY_DATA), true);
- } else {
- throw new RuntimeException("SMS is not enabled");
- }
+ smsManager.sendMessageSync(device.getPhone(), command.getString(Command.KEY_DATA), true);
} else {
throw new RuntimeException("Command " + command.getType() + " is not supported");
}
} else {
- DeviceSession deviceSession = Context.getConnectionManager().getDeviceSession(deviceId);
+ DeviceSession deviceSession = connectionManager.getDeviceSession(deviceId);
if (deviceSession != null) {
if (deviceSession.supportsLiveCommands()) {
deviceSession.sendCommand(command);
@@ -93,76 +102,22 @@ public class CommandsManager extends ExtendedObjectManager<Command> {
return true;
}
- public Collection<Long> getSupportedCommands(long deviceId) {
- List<Long> result = new ArrayList<>();
- Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId);
- for (long commandId : getAllDeviceItems(deviceId)) {
- Command command = getById(commandId);
- if (lastPosition != null) {
- BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol());
- if (command.getTextChannel() && protocol.getSupportedTextCommands().contains(command.getType())
- || !command.getTextChannel()
- && protocol.getSupportedDataCommands().contains(command.getType())) {
- result.add(commandId);
- }
- } else if (command.getType().equals(Command.TYPE_CUSTOM)) {
- result.add(commandId);
- }
- }
- return result;
- }
-
- public Collection<Typed> getCommandTypes(long deviceId, boolean textChannel) {
- Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId);
- if (lastPosition != null) {
- return getCommandTypes(lastPosition.getProtocol(), textChannel);
- } else {
- return Collections.singletonList(new Typed(Command.TYPE_CUSTOM));
- }
- }
-
- public Collection<Typed> getCommandTypes(String protocolName, boolean textChannel) {
- List<Typed> result = new ArrayList<>();
- BaseProtocol protocol = Context.getServerManager().getProtocol(protocolName);
- Collection<String> commands;
- commands = textChannel ? protocol.getSupportedTextCommands() : protocol.getSupportedDataCommands();
- for (String commandKey : commands) {
- result.add(new Typed(commandKey));
- }
- return result;
- }
-
- public Collection<Typed> getAllCommandTypes() {
- List<Typed> result = new ArrayList<>();
- Field[] fields = Command.class.getDeclaredFields();
- for (Field field : fields) {
- if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("TYPE_")) {
- try {
- result.add(new Typed(field.get(null).toString()));
- } catch (IllegalArgumentException | IllegalAccessException error) {
- LOGGER.warn("Get command types error", error);
- }
- }
- }
- return result;
- }
-
private Queue<Command> getDeviceQueue(long deviceId) {
Queue<Command> deviceQueue;
try {
- readLock();
+ lock.readLock().lock();
deviceQueue = deviceQueues.get(deviceId);
} finally {
- readUnlock();
+ lock.readLock().unlock();
}
if (deviceQueue != null) {
return deviceQueue;
} else {
try {
- writeLock();
+ lock.writeLock().lock();
return deviceQueues.computeIfAbsent(deviceId, key -> new ConcurrentLinkedQueue<>());
} finally {
- writeUnlock();
+ lock.writeLock().unlock();
}
}
}
@@ -174,10 +129,10 @@ public class CommandsManager extends ExtendedObjectManager<Command> {
public Collection<Command> readQueuedCommands(long deviceId, int count) {
Queue<Command> deviceQueue;
try {
- readLock();
+ lock.readLock().lock();
deviceQueue = deviceQueues.get(deviceId);
} finally {
- readUnlock();
+ lock.readLock().unlock();
}
Collection<Command> result = new ArrayList<>();
if (deviceQueue != null) {
diff --git a/src/main/java/org/traccar/database/DataManager.java b/src/main/java/org/traccar/database/DataManager.java
index b5966ca9e..1426daea3 100644
--- a/src/main/java/org/traccar/database/DataManager.java
+++ b/src/main/java/org/traccar/database/DataManager.java
@@ -50,8 +50,6 @@ import java.lang.reflect.Method;
import java.net.URL;
import java.util.Collection;
import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
public class DataManager {
@@ -205,14 +203,9 @@ public class DataManager {
}
public Collection<Position> getLatestPositions() throws StorageException {
- List<Position> positions = new LinkedList<>();
- List<Device> devices = storage.getObjects(Device.class, new Request(new Columns.Include("positionId")));
- for (Device device : devices) {
- positions.addAll(storage.getObjects(Position.class, new Request(
- new Columns.All(),
- new Condition.Equals("id", "id", device.getPositionId()))));
- }
- return positions;
+ return storage.getObjects(Position.class, new Request(
+ new Columns.All(),
+ new Condition.LatestPositions()));
}
public Server getServer() throws StorageException {
diff --git a/src/main/java/org/traccar/database/PermissionsManager.java b/src/main/java/org/traccar/database/PermissionsManager.java
index 29bb8a27b..4d5c59fcc 100644
--- a/src/main/java/org/traccar/database/PermissionsManager.java
+++ b/src/main/java/org/traccar/database/PermissionsManager.java
@@ -20,7 +20,6 @@ import org.slf4j.LoggerFactory;
import org.traccar.Context;
import org.traccar.model.BaseModel;
import org.traccar.model.Calendar;
-import org.traccar.model.Command;
import org.traccar.model.Device;
import org.traccar.model.Driver;
import org.traccar.model.Geofence;
@@ -274,18 +273,6 @@ public class PermissionsManager {
}
}
- public void checkLimitCommands(long userId) throws SecurityException {
- if (!getUserAdmin(userId) && (server.getLimitCommands() || getUserLimitCommands(userId))) {
- throw new SecurityException("Account has limit sending commands");
- }
- }
-
- public void checkUserDeviceCommand(long userId, long deviceId, long commandId) throws SecurityException {
- if (!getUserAdmin(userId) && Context.getCommandsManager().checkDeviceCommand(deviceId, commandId)) {
- throw new SecurityException("Command can not be sent to this device");
- }
- }
-
public void checkUserEnabled(long userId) throws SecurityException {
User user = getUser(userId);
if (user == null) {
@@ -367,21 +354,9 @@ public class PermissionsManager {
if (object.equals(Device.class)) {
checkDevice(userId, objectId);
- } else if (object.equals(Command.class)) {
- manager = Context.getCommandsManager();
} else {
throw new IllegalArgumentException("Unknown object type");
}
-
- if (manager != null && !manager.checkItemPermission(userId, objectId) && !getUserAdmin(userId)) {
- checkManager(userId);
- for (long managedUserId : usersManager.getManagedItems(userId)) {
- if (manager.checkItemPermission(managedUserId, objectId)) {
- return;
- }
- }
- throw new SecurityException("Type " + object + " access denied");
- }
}
public void refreshAllUsersPermissions() {
@@ -390,7 +365,6 @@ public class PermissionsManager {
}
Context.getCalendarManager().refreshUserItems();
Context.getDriversManager().refreshUserItems();
- Context.getCommandsManager().refreshUserItems();
Context.getMaintenancesManager().refreshUserItems();
if (Context.getNotificationManager() != null) {
Context.getNotificationManager().refreshUserItems();
@@ -402,7 +376,6 @@ public class PermissionsManager {
Context.getGeofenceManager().refreshExtendedPermissions();
}
Context.getDriversManager().refreshExtendedPermissions();
- Context.getCommandsManager().refreshExtendedPermissions();
Context.getMaintenancesManager().refreshExtendedPermissions();
}
@@ -420,8 +393,6 @@ public class PermissionsManager {
Context.getDriversManager().refreshUserItems();
} else if (permission.getPropertyClass().equals(Calendar.class)) {
Context.getCalendarManager().refreshUserItems();
- } else if (permission.getPropertyClass().equals(Command.class)) {
- Context.getCommandsManager().refreshUserItems();
} else if (permission.getPropertyClass().equals(Maintenance.class)) {
Context.getMaintenancesManager().refreshUserItems();
} else if (permission.getPropertyClass().equals(Order.class)) {
@@ -435,8 +406,6 @@ public class PermissionsManager {
Context.getGeofenceManager().refreshExtendedPermissions();
} else if (permission.getPropertyClass().equals(Driver.class)) {
Context.getDriversManager().refreshExtendedPermissions();
- } else if (permission.getPropertyClass().equals(Command.class)) {
- Context.getCommandsManager().refreshExtendedPermissions();
} else if (permission.getPropertyClass().equals(Maintenance.class)) {
Context.getMaintenancesManager().refreshExtendedPermissions();
} else if (permission.getPropertyClass().equals(Order.class)) {
diff --git a/src/main/java/org/traccar/model/Server.java b/src/main/java/org/traccar/model/Server.java
index b48e84939..7cffd7eac 100644
--- a/src/main/java/org/traccar/model/Server.java
+++ b/src/main/java/org/traccar/model/Server.java
@@ -22,7 +22,7 @@ import org.traccar.storage.StorageName;
@StorageName("tc_servers")
@JsonIgnoreProperties(ignoreUnknown = true)
-public class Server extends ExtendedModel {
+public class Server extends ExtendedModel implements UserRestrictions {
private boolean registration;
@@ -36,6 +36,7 @@ public class Server extends ExtendedModel {
private boolean readonly;
+ @Override
public boolean getReadonly() {
return readonly;
}
@@ -46,6 +47,7 @@ public class Server extends ExtendedModel {
private boolean deviceReadonly;
+ @Override
public boolean getDeviceReadonly() {
return deviceReadonly;
}
@@ -146,6 +148,7 @@ public class Server extends ExtendedModel {
private boolean limitCommands;
+ @Override
public boolean getLimitCommands() {
return limitCommands;
}
@@ -156,6 +159,7 @@ public class Server extends ExtendedModel {
private boolean disableReports;
+ @Override
public boolean getDisableReports() {
return disableReports;
}
diff --git a/src/main/java/org/traccar/model/User.java b/src/main/java/org/traccar/model/User.java
index 6a67f3276..12fd03d45 100644
--- a/src/main/java/org/traccar/model/User.java
+++ b/src/main/java/org/traccar/model/User.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2013 - 2022 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@ import org.traccar.storage.StorageName;
import java.util.Date;
@StorageName("tc_users")
-public class User extends ExtendedModel {
+public class User extends ExtendedModel implements UserRestrictions {
private String name;
@@ -69,6 +69,7 @@ public class User extends ExtendedModel {
private boolean readonly;
+ @Override
public boolean getReadonly() {
return readonly;
}
@@ -195,6 +196,7 @@ public class User extends ExtendedModel {
private boolean deviceReadonly;
+ @Override
public boolean getDeviceReadonly() {
return deviceReadonly;
}
@@ -222,6 +224,7 @@ public class User extends ExtendedModel {
private boolean limitCommands;
+ @Override
public boolean getLimitCommands() {
return limitCommands;
}
@@ -234,6 +237,7 @@ public class User extends ExtendedModel {
private boolean disableReports;
+ @Override
public boolean getDisableReports() {
return disableReports;
}
diff --git a/src/main/java/org/traccar/model/UserRestrictions.java b/src/main/java/org/traccar/model/UserRestrictions.java
new file mode 100644
index 000000000..2e4e5e363
--- /dev/null
+++ b/src/main/java/org/traccar/model/UserRestrictions.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2022 Anton Tananaev (anton@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.model;
+
+public interface UserRestrictions {
+ boolean getReadonly();
+ boolean getDeviceReadonly();
+ boolean getLimitCommands();
+ boolean getDisableReports();
+}
diff --git a/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java b/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java
index 178ec344f..3574dd2a3 100644
--- a/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/OsmAndProtocolDecoder.java
@@ -21,10 +21,8 @@ import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.QueryStringDecoder;
import org.traccar.BaseHttpProtocolDecoder;
-import org.traccar.Context;
import org.traccar.session.DeviceSession;
import org.traccar.Protocol;
-import org.traccar.database.CommandsManager;
import org.traccar.helper.DateUtil;
import org.traccar.model.CellTower;
import org.traccar.model.Command;
@@ -178,11 +176,8 @@ public class OsmAndProtocolDecoder extends BaseHttpProtocolDecoder {
if (position.getDeviceId() != 0) {
String response = null;
- CommandsManager commandsManager = Context.getCommandsManager();
- if (commandsManager != null) {
- for (Command command : commandsManager.readQueuedCommands(position.getDeviceId(), 1)) {
- response = command.getString(Command.KEY_DATA);
- }
+ for (Command command : getCommandsManager().readQueuedCommands(position.getDeviceId(), 1)) {
+ response = command.getString(Command.KEY_DATA);
}
if (response != null) {
sendResponse(channel, HttpResponseStatus.OK, Unpooled.copiedBuffer(response, StandardCharsets.UTF_8));
diff --git a/src/main/java/org/traccar/storage/DatabaseStorage.java b/src/main/java/org/traccar/storage/DatabaseStorage.java
index 91dd6b077..fc468182e 100644
--- a/src/main/java/org/traccar/storage/DatabaseStorage.java
+++ b/src/main/java/org/traccar/storage/DatabaseStorage.java
@@ -209,6 +209,11 @@ public class DatabaseStorage extends Storage {
} else {
results.put(Permission.getKey(condition.getPropertyClass()), condition.getPropertyId());
}
+ } else if (genericCondition instanceof Condition.LatestPositions) {
+ var condition = (Condition.LatestPositions) genericCondition;
+ if (condition.getDeviceId() > 0) {
+ results.put("deviceId", condition.getDeviceId());
+ }
}
return results;
}
@@ -262,6 +267,17 @@ public class DatabaseStorage extends Storage {
result.append(formatPermissionQuery(condition));
result.append(")");
+ } else if (genericCondition instanceof Condition.LatestPositions) {
+
+ var condition = (Condition.LatestPositions) genericCondition;
+ result.append("id IN (");
+ result.append("SELECT positionId FROM ");
+ result.append(getStorageName(Device.class));
+ if (condition.getDeviceId() > 0) {
+ result.append(" WHERE id = :deviceId");
+ }
+ result.append(")");
+
}
}
return result.toString();
diff --git a/src/main/java/org/traccar/storage/query/Condition.java b/src/main/java/org/traccar/storage/query/Condition.java
index 91ede236c..136b0402b 100644
--- a/src/main/java/org/traccar/storage/query/Condition.java
+++ b/src/main/java/org/traccar/storage/query/Condition.java
@@ -196,4 +196,20 @@ public interface Condition {
}
}
+ class LatestPositions implements Condition {
+ private final long deviceId;
+
+ public LatestPositions(long deviceId) {
+ this.deviceId = deviceId;
+ }
+
+ public LatestPositions() {
+ this(0);
+ }
+
+ public long getDeviceId() {
+ return deviceId;
+ }
+ }
+
}
diff --git a/src/test/java/org/traccar/BaseTest.java b/src/test/java/org/traccar/BaseTest.java
index a34524c43..1652a6694 100644
--- a/src/test/java/org/traccar/BaseTest.java
+++ b/src/test/java/org/traccar/BaseTest.java
@@ -2,6 +2,7 @@ package org.traccar;
import io.netty.channel.Channel;
import org.traccar.config.Config;
+import org.traccar.database.CommandsManager;
import org.traccar.database.IdentityManager;
import org.traccar.database.MediaManager;
import org.traccar.database.StatisticsManager;
@@ -52,6 +53,7 @@ public class BaseTest {
decoder.setConnectionManager(connectionManager);
decoder.setStatisticsManager(mock(StatisticsManager.class));
decoder.setMediaManager(mock(MediaManager.class));
+ decoder.setCommandsManager(mock(CommandsManager.class));
return decoder;
}