aboutsummaryrefslogtreecommitdiff
path: root/src/org/traccar
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/traccar')
-rw-r--r--src/org/traccar/Context.java12
-rw-r--r--src/org/traccar/api/BaseObjectResource.java7
-rw-r--r--src/org/traccar/api/resource/CommandResource.java46
-rw-r--r--src/org/traccar/api/resource/CommandTypeResource.java8
-rw-r--r--src/org/traccar/database/CommandsManager.java136
-rw-r--r--src/org/traccar/database/DataManager.java3
-rw-r--r--src/org/traccar/database/DeviceManager.java51
-rw-r--r--src/org/traccar/database/PermissionsManager.java26
-rw-r--r--src/org/traccar/model/Command.java18
-rw-r--r--src/org/traccar/model/Server.java10
-rw-r--r--src/org/traccar/model/User.java10
11 files changed, 269 insertions, 58 deletions
diff --git a/src/org/traccar/Context.java b/src/org/traccar/Context.java
index 87d8257ee..210d52429 100644
--- a/src/org/traccar/Context.java
+++ b/src/org/traccar/Context.java
@@ -26,6 +26,7 @@ import java.util.Properties;
import org.apache.velocity.app.VelocityEngine;
import org.eclipse.jetty.util.URIUtil;
import org.traccar.database.CalendarManager;
+import org.traccar.database.CommandsManager;
import org.traccar.database.AttributesManager;
import org.traccar.database.BaseObjectManager;
import org.traccar.database.ConnectionManager;
@@ -56,6 +57,7 @@ import org.traccar.helper.Log;
import org.traccar.model.Attribute;
import org.traccar.model.BaseModel;
import org.traccar.model.Calendar;
+import org.traccar.model.Command;
import org.traccar.model.Device;
import org.traccar.model.Driver;
import org.traccar.model.Geofence;
@@ -213,6 +215,12 @@ public final class Context {
return driversManager;
}
+ private static CommandsManager commandsManager;
+
+ public static CommandsManager getCommandsManager() {
+ return commandsManager;
+ }
+
private static StatisticsManager statisticsManager;
public static StatisticsManager getStatisticsManager() {
@@ -392,6 +400,8 @@ public final class Context {
driversManager = new DriversManager(dataManager);
+ commandsManager = new CommandsManager(dataManager);
+
statisticsManager = new StatisticsManager();
if (config.getBoolean("sms.smpp.enable")) {
@@ -421,6 +431,8 @@ 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;
}
return null;
}
diff --git a/src/org/traccar/api/BaseObjectResource.java b/src/org/traccar/api/BaseObjectResource.java
index b13dc2e71..4315832b5 100644
--- a/src/org/traccar/api/BaseObjectResource.java
+++ b/src/org/traccar/api/BaseObjectResource.java
@@ -32,6 +32,7 @@ import org.traccar.database.ExtendedObjectManager;
import org.traccar.database.ManagableObjects;
import org.traccar.database.SimpleObjectManager;
import org.traccar.model.BaseModel;
+import org.traccar.model.Command;
import org.traccar.model.Device;
import org.traccar.model.Group;
import org.traccar.model.User;
@@ -73,6 +74,8 @@ public abstract class BaseObjectResource<T extends BaseModel> extends BaseResour
if (baseClass.equals(Device.class)) {
Context.getPermissionsManager().checkDeviceReadonly(getUserId());
Context.getPermissionsManager().checkDeviceLimit(getUserId());
+ } else if (baseClass.equals(Command.class)) {
+ Context.getPermissionsManager().checkLimitCommands(getUserId());
}
BaseObjectManager<T> manager = Context.getManager(baseClass);
@@ -98,6 +101,8 @@ public abstract class BaseObjectResource<T extends BaseModel> extends BaseResour
} else if (baseClass.equals(User.class)) {
User before = Context.getPermissionsManager().getUser(entity.getId());
Context.getPermissionsManager().checkUserUpdate(getUserId(), before, (User) entity);
+ } else if (baseClass.equals(Command.class)) {
+ Context.getPermissionsManager().checkLimitCommands(getUserId());
}
Context.getPermissionsManager().checkPermission(baseClass, getUserId(), entity.getId());
@@ -118,6 +123,8 @@ public abstract class BaseObjectResource<T extends BaseModel> extends BaseResour
Context.getPermissionsManager().checkReadonly(getUserId());
if (baseClass.equals(Device.class)) {
Context.getPermissionsManager().checkDeviceReadonly(getUserId());
+ } else if (baseClass.equals(Command.class)) {
+ Context.getPermissionsManager().checkLimitCommands(getUserId());
}
Context.getPermissionsManager().checkPermission(baseClass, getUserId(), id);
diff --git a/src/org/traccar/api/resource/CommandResource.java b/src/org/traccar/api/resource/CommandResource.java
index 9ed92d3d5..f7e7d4f8c 100644
--- a/src/org/traccar/api/resource/CommandResource.java
+++ b/src/org/traccar/api/resource/CommandResource.java
@@ -16,26 +16,62 @@
package org.traccar.api.resource;
import org.traccar.Context;
-import org.traccar.api.BaseResource;
+import org.traccar.api.ExtendedObjectResource;
+import org.traccar.database.CommandsManager;
import org.traccar.model.Command;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@Path("commands")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
-public class CommandResource extends BaseResource {
+public class CommandResource extends ExtendedObjectResource<Command> {
+
+ public CommandResource() {
+ super(Command.class);
+ }
+
+ @GET
+ @Path("send")
+ public Collection<Command> get(@QueryParam("deviceId") long deviceId,
+ @QueryParam("textChannel") boolean textChannel) throws SQLException {
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ CommandsManager commandsManager = Context.getCommandsManager();
+ Set<Long> result = null;
+ result = new HashSet<>(commandsManager.getUserItems(getUserId()));
+ result.retainAll(commandsManager.getProperCommands(deviceId, textChannel));
+ return commandsManager.getItems(result);
+ }
@POST
- public Response add(Command entity) throws Exception {
+ @Path("send")
+ public Response send(Command entity) throws Exception {
Context.getPermissionsManager().checkReadonly(getUserId());
- Context.getPermissionsManager().checkDevice(getUserId(), entity.getDeviceId());
- Context.getDeviceManager().sendCommand(entity);
+ Command command = entity;
+ long deviceId = command.getDeviceId();
+ long id = command.getId();
+ if (deviceId != 0 && id != 0) {
+ Context.getPermissionsManager().checkPermission(Command.class, getUserId(), id);
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ Context.getPermissionsManager().checkUserDeviceCommand(getUserId(), deviceId, id);
+ Context.getCommandsManager().sendCommand(id, deviceId);
+ } else {
+ Context.getPermissionsManager().checkLimitCommands(getUserId());
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ Context.getCommandsManager().sendCommand(command);
+ }
return Response.ok(entity).build();
}
diff --git a/src/org/traccar/api/resource/CommandTypeResource.java b/src/org/traccar/api/resource/CommandTypeResource.java
index d5d220547..30f9300cb 100644
--- a/src/org/traccar/api/resource/CommandTypeResource.java
+++ b/src/org/traccar/api/resource/CommandTypeResource.java
@@ -36,8 +36,12 @@ public class CommandTypeResource extends BaseResource {
@GET
public Collection<CommandType> get(@QueryParam("deviceId") long deviceId,
@QueryParam("textChannel") boolean textChannel) {
- Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
- return Context.getDeviceManager().getCommandTypes(deviceId, textChannel);
+ if (deviceId != 0) {
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ return Context.getCommandsManager().getCommandTypes(deviceId, textChannel);
+ } else {
+ return Context.getCommandsManager().getAllCommandTypes();
+ }
}
}
diff --git a/src/org/traccar/database/CommandsManager.java b/src/org/traccar/database/CommandsManager.java
new file mode 100644
index 000000000..9f97c929c
--- /dev/null
+++ b/src/org/traccar/database/CommandsManager.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.database;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.traccar.BaseProtocol;
+import org.traccar.Context;
+import org.traccar.helper.Log;
+import org.traccar.model.Command;
+import org.traccar.model.CommandType;
+import org.traccar.model.Position;
+
+public class CommandsManager extends ExtendedObjectManager<Command> {
+
+ private boolean fallbackToText;
+
+ public CommandsManager(DataManager dataManager) {
+ super(dataManager, Command.class);
+ fallbackToText = Context.getConfig().getBoolean("command.fallbackToSms");
+ }
+
+ public boolean checkDeviceCommand(long deviceId, long commandId) {
+ return getAllDeviceItems(deviceId).contains(commandId);
+ }
+
+ public void sendCommand(Command command) throws Exception {
+ sendCommand(command, command.getDeviceId(), fallbackToText);
+ }
+
+ public void sendCommand(long commandId, long deviceId) throws Exception {
+ sendCommand(getById(commandId), deviceId, false);
+ }
+
+ public void sendCommand(Command command, long deviceId, boolean fallbackToText) throws Exception {
+ 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);
+ } else if (command.getType().equals(Command.TYPE_CUSTOM)) {
+ if (Context.getSmppManager() != null) {
+ Context.getSmppManager().sendMessageSync(phone, command.getString(Command.KEY_DATA), true);
+ } else {
+ throw new RuntimeException("SMPP client is not enabled");
+ }
+ } else {
+ throw new RuntimeException("Command " + command.getType() + " is not supported");
+ }
+ } else {
+ ActiveDevice activeDevice = Context.getConnectionManager().getActiveDevice(deviceId);
+ if (activeDevice != null) {
+ activeDevice.sendCommand(command);
+ } else {
+ if (fallbackToText) {
+ command.setTextChannel(true);
+ sendCommand(command, deviceId, false);
+ } else {
+ throw new RuntimeException("Device is not online");
+ }
+ }
+ }
+ }
+
+ public Collection<Long> getProperCommands(long deviceId, boolean textChannel) {
+ List<Long> result = new ArrayList<>();
+ Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId);
+ for (long commandId : getAllDeviceItems(deviceId)) {
+ Command command = getById(commandId);
+ if (command.getTextChannel() == textChannel) {
+ if (lastPosition != null) {
+ BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol());
+ Collection<String> protocolCommands =
+ textChannel ? protocol.getSupportedTextCommands() : protocol.getSupportedDataCommands();
+ if (protocolCommands.contains(command.getType())) {
+ result.add(commandId);
+ }
+ } else if (command.getType().equals(Command.TYPE_CUSTOM)) {
+ result.add(commandId);
+ }
+ }
+ }
+ return result;
+ }
+
+ public Collection<CommandType> getCommandTypes(long deviceId, boolean textChannel) {
+ List<CommandType> result = new ArrayList<>();
+ Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId);
+ if (lastPosition != null) {
+ BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol());
+ Collection<String> commands;
+ commands = textChannel ? protocol.getSupportedTextCommands() : protocol.getSupportedDataCommands();
+ for (String commandKey : commands) {
+ result.add(new CommandType(commandKey));
+ }
+ } else {
+ result.add(new CommandType(Command.TYPE_CUSTOM));
+ }
+ return result;
+ }
+
+ public Collection<CommandType> getAllCommandTypes() {
+ List<CommandType> 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 CommandType(field.get(null).toString()));
+ } catch (IllegalArgumentException | IllegalAccessException error) {
+ Log.warning(error);
+ }
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java
index 4535a9c38..261541b4d 100644
--- a/src/org/traccar/database/DataManager.java
+++ b/src/org/traccar/database/DataManager.java
@@ -51,6 +51,7 @@ import org.traccar.model.ManagedUser;
import org.traccar.model.Permission;
import org.traccar.model.BaseModel;
import org.traccar.model.Calendar;
+import org.traccar.model.Command;
import org.traccar.model.Position;
import org.traccar.model.Server;
import org.traccar.model.Statistics;
@@ -390,6 +391,8 @@ public class DataManager {
return Attribute.class;
case "calendar":
return Calendar.class;
+ case "command":
+ return Command.class;
default:
throw new ClassNotFoundException();
}
diff --git a/src/org/traccar/database/DeviceManager.java b/src/org/traccar/database/DeviceManager.java
index 2157e738d..1eb90b7eb 100644
--- a/src/org/traccar/database/DeviceManager.java
+++ b/src/org/traccar/database/DeviceManager.java
@@ -16,7 +16,6 @@
package org.traccar.database;
import java.sql.SQLException;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
@@ -26,12 +25,9 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
-import org.traccar.BaseProtocol;
import org.traccar.Config;
import org.traccar.Context;
import org.traccar.helper.Log;
-import org.traccar.model.Command;
-import org.traccar.model.CommandType;
import org.traccar.model.Device;
import org.traccar.model.DeviceState;
import org.traccar.model.DeviceTotalDistance;
@@ -55,8 +51,6 @@ public class DeviceManager extends BaseObjectManager<Device> implements Identity
private final Map<Long, DeviceState> deviceStates = new ConcurrentHashMap<>();
- private boolean fallbackToText;
-
public DeviceManager(DataManager dataManager) {
super(dataManager, Device.class);
this.config = Context.getConfig();
@@ -68,7 +62,6 @@ public class DeviceManager extends BaseObjectManager<Device> implements Identity
}
dataRefreshDelay = config.getLong("database.refreshDelay", DEFAULT_REFRESH_DELAY) * 1000;
lookupGroupsAttribute = config.getBoolean("deviceManager.lookupGroupsAttribute");
- fallbackToText = config.getBoolean("command.fallbackToSms");
refreshLastPositions();
}
@@ -344,50 +337,6 @@ public class DeviceManager extends BaseObjectManager<Device> implements Identity
}
}
- public void sendCommand(Command command) throws Exception {
- long deviceId = command.getDeviceId();
- if (command.getTextChannel()) {
- Position lastPosition = getLastPosition(deviceId);
- if (lastPosition != null) {
- BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol());
- protocol.sendTextCommand(getById(deviceId).getPhone(), command);
- } else if (command.getType().equals(Command.TYPE_CUSTOM)) {
- Context.getSmppManager().sendMessageSync(getById(deviceId).getPhone(),
- command.getString(Command.KEY_DATA), true);
- } else {
- throw new RuntimeException("Command " + command.getType() + " is not supported");
- }
- } else {
- ActiveDevice activeDevice = Context.getConnectionManager().getActiveDevice(deviceId);
- if (activeDevice != null) {
- activeDevice.sendCommand(command);
- } else {
- if (fallbackToText) {
- command.setTextChannel(true);
- sendCommand(command);
- } else {
- throw new RuntimeException("Device is not online");
- }
- }
- }
- }
-
- public Collection<CommandType> getCommandTypes(long deviceId, boolean textChannel) {
- List<CommandType> result = new ArrayList<>();
- Position lastPosition = Context.getDeviceManager().getLastPosition(deviceId);
- if (lastPosition != null) {
- BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol());
- Collection<String> commands;
- commands = textChannel ? protocol.getSupportedTextCommands() : protocol.getSupportedDataCommands();
- for (String commandKey : commands) {
- result.add(new CommandType(commandKey));
- }
- } else {
- result.add(new CommandType(Command.TYPE_CUSTOM));
- }
- return result;
- }
-
public DeviceState getDeviceState(long deviceId) {
DeviceState deviceState = deviceStates.get(deviceId);
if (deviceState == null) {
diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java
index 0708cc5c9..3da99dd13 100644
--- a/src/org/traccar/database/PermissionsManager.java
+++ b/src/org/traccar/database/PermissionsManager.java
@@ -20,6 +20,7 @@ import org.traccar.helper.Log;
import org.traccar.model.Attribute;
import org.traccar.model.BaseModel;
import org.traccar.model.Calendar;
+import org.traccar.model.Command;
import org.traccar.model.Device;
import org.traccar.model.Driver;
import org.traccar.model.Geofence;
@@ -197,6 +198,11 @@ public class PermissionsManager {
return user != null && user.getDeviceReadonly();
}
+ public boolean isLimitCommands(long userId) {
+ User user = getUser(userId);
+ return user != null && user.getLimitCommands();
+ }
+
public void checkReadonly(long userId) throws SecurityException {
if (!isAdmin(userId) && (server.getReadonly() || isReadonly(userId))) {
throw new SecurityException("Account is readonly");
@@ -209,6 +215,18 @@ public class PermissionsManager {
}
}
+ public void checkLimitCommands(long userId) throws SecurityException {
+ if (!isAdmin(userId) && (server.getLimitCommands() || isLimitCommands(userId))) {
+ throw new SecurityException("Account has limit sending commands");
+ }
+ }
+
+ public void checkUserDeviceCommand(long userId, long deviceId, long commandId) throws SecurityException {
+ if (!isAdmin(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) {
@@ -300,6 +318,8 @@ public class PermissionsManager {
manager = Context.getDriversManager();
} else if (object.equals(Calendar.class)) {
manager = Context.getCalendarManager();
+ } else if (object.equals(Command.class)) {
+ manager = Context.getCommandsManager();
} else {
throw new IllegalArgumentException("Unknown object type");
}
@@ -322,6 +342,7 @@ public class PermissionsManager {
Context.getCalendarManager().refreshUserItems();
Context.getDriversManager().refreshUserItems();
Context.getAttributesManager().refreshUserItems();
+ Context.getCommandsManager().refreshUserItems();
if (Context.getNotificationManager() != null) {
Context.getNotificationManager().refresh();
}
@@ -333,6 +354,7 @@ public class PermissionsManager {
}
Context.getDriversManager().refreshExtendedPermissions();
Context.getAttributesManager().refreshExtendedPermissions();
+ Context.getCommandsManager().refreshExtendedPermissions();
}
public void refreshPermissions(Permission permission) {
@@ -351,6 +373,8 @@ public class PermissionsManager {
Context.getAttributesManager().refreshUserItems();
} else if (permission.getPropertyClass().equals(Calendar.class)) {
Context.getCalendarManager().refreshUserItems();
+ } else if (permission.getPropertyClass().equals(Command.class)) {
+ Context.getCommandsManager().refreshUserItems();
}
} else if (permission.getOwnerClass().equals(Device.class) || permission.getOwnerClass().equals(Group.class)) {
if (permission.getPropertyClass().equals(Geofence.class) && Context.getGeofenceManager() != null) {
@@ -359,6 +383,8 @@ public class PermissionsManager {
Context.getDriversManager().refreshExtendedPermissions();
} else if (permission.getPropertyClass().equals(Attribute.class)) {
Context.getAttributesManager().refreshExtendedPermissions();
+ } else if (permission.getPropertyClass().equals(Command.class)) {
+ Context.getCommandsManager().refreshExtendedPermissions();
}
}
}
diff --git a/src/org/traccar/model/Command.java b/src/org/traccar/model/Command.java
index 6a48b14e9..67134dc7d 100644
--- a/src/org/traccar/model/Command.java
+++ b/src/org/traccar/model/Command.java
@@ -15,6 +15,8 @@
*/
package org.traccar.model;
+import org.traccar.database.QueryIgnore;
+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
@@ -85,4 +87,20 @@ public class Command extends Message {
this.textChannel = textChannel;
}
+ @QueryIgnore
+ @Override
+ public long getDeviceId() {
+ return super.getDeviceId();
+ }
+
+ private String description;
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
}
diff --git a/src/org/traccar/model/Server.java b/src/org/traccar/model/Server.java
index bfe881479..072e85d55 100644
--- a/src/org/traccar/model/Server.java
+++ b/src/org/traccar/model/Server.java
@@ -147,4 +147,14 @@ public class Server extends ExtendedModel {
public void setCoordinateFormat(String coordinateFormat) {
this.coordinateFormat = coordinateFormat;
}
+
+ private boolean limitCommands;
+
+ public boolean getLimitCommands() {
+ return limitCommands;
+ }
+
+ public void setLimitCommands(boolean limitCommands) {
+ this.limitCommands = limitCommands;
+ }
}
diff --git a/src/org/traccar/model/User.java b/src/org/traccar/model/User.java
index 043c23036..5d89dcfae 100644
--- a/src/org/traccar/model/User.java
+++ b/src/org/traccar/model/User.java
@@ -210,6 +210,16 @@ public class User extends ExtendedModel {
}
}
+ private boolean limitCommands;
+
+ public boolean getLimitCommands() {
+ return limitCommands;
+ }
+
+ public void setLimitCommands(boolean limitCommands) {
+ this.limitCommands = limitCommands;
+ }
+
@QueryIgnore
public String getPassword() {
return null;