aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/org/traccar/BaseEventHandler.java31
-rw-r--r--src/org/traccar/BasePipelineFactory.java33
-rw-r--r--src/org/traccar/api/AsyncSocket.java7
-rw-r--r--src/org/traccar/api/resource/EventResource.java39
-rw-r--r--src/org/traccar/database/ConnectionManager.java42
-rw-r--r--src/org/traccar/database/DataManager.java31
-rw-r--r--src/org/traccar/events/CommandResultEventHandler.java18
-rw-r--r--src/org/traccar/events/MotionEventHandler.java55
-rw-r--r--src/org/traccar/events/OverspeedEventHandler.java79
-rw-r--r--src/org/traccar/model/Device.java13
-rw-r--r--src/org/traccar/model/Event.java74
-rw-r--r--src/org/traccar/web/WebServer.java4
12 files changed, 418 insertions, 8 deletions
diff --git a/src/org/traccar/BaseEventHandler.java b/src/org/traccar/BaseEventHandler.java
new file mode 100644
index 000000000..3c2016af0
--- /dev/null
+++ b/src/org/traccar/BaseEventHandler.java
@@ -0,0 +1,31 @@
+package org.traccar;
+
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+public abstract class BaseEventHandler extends BaseDataHandler {
+
+ private boolean isLastPosition = false;
+
+ public boolean isLastPosition() {
+ return isLastPosition;
+ }
+
+ @Override
+ protected Position handlePosition(Position position) {
+
+ Position lastPosition = Context.getConnectionManager().getLastPosition(position.getDeviceId());
+ if (lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) >= 0) {
+ isLastPosition = true;
+ }
+
+ Event event = analizePosition(position);
+ if (event != null) {
+ Context.getConnectionManager().updateEvent(event);
+ }
+ return position;
+ }
+
+ protected abstract Event analizePosition(Position position);
+
+}
diff --git a/src/org/traccar/BasePipelineFactory.java b/src/org/traccar/BasePipelineFactory.java
index 6e350f61d..55820deb7 100644
--- a/src/org/traccar/BasePipelineFactory.java
+++ b/src/org/traccar/BasePipelineFactory.java
@@ -29,6 +29,9 @@ import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.handler.logging.LoggingHandler;
import org.jboss.netty.handler.timeout.IdleStateHandler;
+import org.traccar.events.CommandResultEventHandler;
+import org.traccar.events.MotionEventHandler;
+import org.traccar.events.OverspeedEventHandler;
import org.traccar.helper.Log;
import java.net.InetSocketAddress;
@@ -44,6 +47,10 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
private LocationProviderHandler locationProviderHandler;
private HemisphereHandler hemisphereHandler;
+ private CommandResultEventHandler commandResultEventHandler;
+ private OverspeedEventHandler overspeedEventHandler;
+ private MotionEventHandler motionEventHandler;
+
private static final class OpenChannelHandler extends SimpleChannelHandler {
private final TrackerServer server;
@@ -122,6 +129,17 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
|| Context.getConfig().hasKey("location.longitudeHemisphere")) {
hemisphereHandler = new HemisphereHandler();
}
+
+ commandResultEventHandler = new CommandResultEventHandler();
+
+ if (Context.getConfig().getBoolean("event.overspeedhandler")) {
+ overspeedEventHandler = new OverspeedEventHandler();
+ }
+
+ if (Context.getConfig().getBoolean("event.motionhandler")) {
+ motionEventHandler = new MotionEventHandler();
+ }
+
}
protected abstract void addSpecificHandlers(ChannelPipeline pipeline);
@@ -162,9 +180,23 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
if (Context.getDataManager() != null) {
pipeline.addLast("dataHandler", new DefaultDataHandler());
}
+
if (Context.getConfig().getBoolean("forward.enable")) {
pipeline.addLast("webHandler", new WebDataHandler(Context.getConfig().getString("forward.url")));
}
+
+ if (commandResultEventHandler != null) {
+ pipeline.addLast("CommandResultEventHandler", commandResultEventHandler);
+ }
+
+ if (overspeedEventHandler != null) {
+ pipeline.addLast("OverspeedEventHandler", overspeedEventHandler);
+ }
+
+ if (motionEventHandler != null) {
+ pipeline.addLast("MotionEventHandler", motionEventHandler);
+ }
+
pipeline.addLast("mainHandler", new MainEventHandler());
return pipeline;
}
@@ -181,5 +213,4 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
}
}
}
-
}
diff --git a/src/org/traccar/api/AsyncSocket.java b/src/org/traccar/api/AsyncSocket.java
index 35e760613..2259f840f 100644
--- a/src/org/traccar/api/AsyncSocket.java
+++ b/src/org/traccar/api/AsyncSocket.java
@@ -20,6 +20,7 @@ import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.traccar.Context;
import org.traccar.database.ConnectionManager;
import org.traccar.model.Device;
+import org.traccar.model.Event;
import org.traccar.model.Position;
import org.traccar.web.JsonConverter;
@@ -32,6 +33,7 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U
private static final String KEY_DEVICES = "devices";
private static final String KEY_POSITIONS = "positions";
+ private static final String KEY_EVENTS = "events";
private long userId;
@@ -65,6 +67,11 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U
sendData(KEY_POSITIONS, Collections.singletonList(position));
}
+ @Override
+ public void onUpdateEvent(Event event) {
+ sendData(KEY_EVENTS, Collections.singletonList(event));
+ }
+
private void sendData(String key, Collection<?> data) {
if (!data.isEmpty() && isConnected()) {
JsonObjectBuilder json = Json.createObjectBuilder();
diff --git a/src/org/traccar/api/resource/EventResource.java b/src/org/traccar/api/resource/EventResource.java
new file mode 100644
index 000000000..e0ad34728
--- /dev/null
+++ b/src/org/traccar/api/resource/EventResource.java
@@ -0,0 +1,39 @@
+package org.traccar.api.resource;
+
+import java.sql.SQLException;
+import java.util.Collection;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+
+import org.traccar.Context;
+import org.traccar.api.BaseResource;
+import org.traccar.model.Event;
+
+@Path("events")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+
+public class EventResource extends BaseResource {
+
+ @Path("{id}")
+ @GET
+ public Event get(@PathParam("id") long id) throws SQLException {
+ Event event = Context.getDataManager().getEvent(id);
+ Context.getPermissionsManager().checkDevice(getUserId(), event.getDeviceId());
+ return event;
+ }
+
+ @GET
+ public Collection<Event> get(
+ @QueryParam("deviceId") long deviceId, @QueryParam("type") String type,
+ @QueryParam("interval") long interval) throws SQLException {
+ Context.getPermissionsManager().checkDevice(getUserId(), deviceId);
+ return Context.getDataManager().getLastEvents(deviceId, type, interval);
+ }
+}
diff --git a/src/org/traccar/database/ConnectionManager.java b/src/org/traccar/database/ConnectionManager.java
index bb9958232..d6728357c 100644
--- a/src/org/traccar/database/ConnectionManager.java
+++ b/src/org/traccar/database/ConnectionManager.java
@@ -23,6 +23,7 @@ import org.traccar.GlobalTimer;
import org.traccar.Protocol;
import org.traccar.helper.Log;
import org.traccar.model.Device;
+import org.traccar.model.Event;
import org.traccar.model.Position;
import java.net.SocketAddress;
@@ -85,14 +86,26 @@ public class ConnectionManager {
return;
}
- device.setStatus(status);
- if (time != null) {
- device.setLastUpdate(time);
+ 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.DEVICE_OFFLINE, deviceId);
+ if (status.equals(Device.STATUS_ONLINE)) {
+ event.setType(Event.DEVICE_ONLINE);
+ }
+ updateEvent(event);
+ }
+ device.setStatus(status);
+
+ Timeout timeout = timeouts.remove(deviceId);
+ if (timeout != null) {
+ timeout.cancel();
+ }
}
- Timeout timeout = timeouts.remove(deviceId);
- if (timeout != null) {
- timeout.cancel();
+ if (time != null) {
+ device.setLastUpdate(time);
}
if (status.equals(Device.STATUS_ONLINE)) {
@@ -134,6 +147,22 @@ public class ConnectionManager {
}
}
+ public synchronized void updateEvent(Event event) {
+ long deviceId = event.getDeviceId();
+ try {
+ Context.getDataManager().addEvent(event);
+ } catch (SQLException error) {
+ Log.warning(error);
+ }
+ for (long userId : Context.getPermissionsManager().getDeviceUsers(deviceId)) {
+ if (listeners.containsKey(userId)) {
+ for (UpdateListener listener : listeners.get(userId)) {
+ listener.onUpdateEvent(event);
+ }
+ }
+ }
+ }
+
public Position getLastPosition(long deviceId) {
return positions.get(deviceId);
}
@@ -154,6 +183,7 @@ public class ConnectionManager {
public interface UpdateListener {
void onUpdateDevice(Device device);
void onUpdatePosition(Position position);
+ void onUpdateEvent(Event event);
}
public synchronized void addListener(long userId, UpdateListener listener) {
diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java
index ac3be45ac..4e14f6c97 100644
--- a/src/org/traccar/database/DataManager.java
+++ b/src/org/traccar/database/DataManager.java
@@ -27,6 +27,7 @@ import org.traccar.Config;
import org.traccar.Context;
import org.traccar.helper.Log;
import org.traccar.model.Device;
+import org.traccar.model.Event;
import org.traccar.model.DevicePermission;
import org.traccar.model.Group;
import org.traccar.model.GroupPermission;
@@ -482,4 +483,34 @@ public class DataManager implements IdentityManager {
.setObject(server)
.executeUpdate();
}
+
+ public Event getEvent(long eventId) throws SQLException {
+ return QueryBuilder.create(dataSource, getQuery("database.selectEvent"))
+ .setLong("id", eventId)
+ .executeQuerySingle(Event.class);
+ }
+
+ public void addEvent(Event event) throws SQLException {
+ event.setId(QueryBuilder.create(dataSource, getQuery("database.insertEvent"), true)
+ .setObject(event)
+ .executeUpdate());
+ }
+
+ public Collection<Event> getEvents(long deviceId, String type, Date from, Date to) throws SQLException {
+ return QueryBuilder.create(dataSource, getQuery("database.selectEvents"))
+ .setLong("deviceId", deviceId)
+ .setString("type", type)
+ .setDate("from", from)
+ .setDate("to", to)
+ .executeQuery(Event.class);
+ }
+
+ public Collection<Event> getLastEvents(long deviceId, String type, long interval) throws SQLException {
+ return QueryBuilder.create(dataSource, getQuery("database.selectLastEvents"))
+ .setLong("deviceId", deviceId)
+ .setString("type", type)
+ .setLong("interval", interval)
+ .executeQuery(Event.class);
+ }
+
}
diff --git a/src/org/traccar/events/CommandResultEventHandler.java b/src/org/traccar/events/CommandResultEventHandler.java
new file mode 100644
index 000000000..8ef015841
--- /dev/null
+++ b/src/org/traccar/events/CommandResultEventHandler.java
@@ -0,0 +1,18 @@
+package org.traccar.events;
+
+import org.traccar.BaseEventHandler;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+public class CommandResultEventHandler extends BaseEventHandler {
+
+ @Override
+ protected Event analizePosition(Position position) {
+ Object cmdResult = position.getAttributes().get(Position.KEY_RESULT);
+ if (cmdResult != null) {
+ return new Event(Event.COMMAND_RESULT, position.getDeviceId(), position.getId());
+ }
+ return null;
+ }
+
+}
diff --git a/src/org/traccar/events/MotionEventHandler.java b/src/org/traccar/events/MotionEventHandler.java
new file mode 100644
index 000000000..d4dd12a39
--- /dev/null
+++ b/src/org/traccar/events/MotionEventHandler.java
@@ -0,0 +1,55 @@
+package org.traccar.events;
+
+import java.sql.SQLException;
+
+import org.traccar.BaseEventHandler;
+import org.traccar.Context;
+import org.traccar.helper.Log;
+import org.traccar.model.Device;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+
+public class MotionEventHandler extends BaseEventHandler {
+
+ private static final double SPEED_THRESHOLD = 0.01;
+ private long suppressRepeated;
+
+ public MotionEventHandler() {
+ suppressRepeated = Context.getConfig().getLong("event.suppressrepeated", 60);
+ }
+
+ @Override
+ protected Event analizePosition(Position position) {
+ Event event = null;
+
+ if (!isLastPosition()) {
+ return event;
+ }
+
+ double speed = position.getSpeed();
+ boolean valid = position.getValid();
+ Device device = Context.getIdentityManager().getDeviceById(position.getDeviceId());
+ if (device == null) {
+ return event;
+ }
+ String motion = device.getMotion();
+ if (valid && speed > SPEED_THRESHOLD && !motion.equals(Device.STATUS_MOVING)) {
+ Context.getConnectionManager().updateDevice(position.getDeviceId(), Device.STATUS_MOVING, null);
+ event = new Event(Event.DEVICE_MOVING, position.getDeviceId(), position.getId());
+ } else if (valid && speed < SPEED_THRESHOLD && motion.equals(Device.STATUS_MOVING)) {
+ Context.getConnectionManager().updateDevice(position.getDeviceId(), Device.STATUS_STOPPED, null);
+ event = new Event(Event.DEVICE_STOPPED, position.getDeviceId(), position.getId());
+ }
+ try {
+ if (event != null && !Context.getDataManager().getLastEvents(
+ position.getDeviceId(), event.getType(), suppressRepeated).isEmpty()) {
+ event = null;
+ }
+
+ } catch (SQLException error) {
+ Log.warning(error);
+ }
+ return event;
+ }
+
+}
diff --git a/src/org/traccar/events/OverspeedEventHandler.java b/src/org/traccar/events/OverspeedEventHandler.java
new file mode 100644
index 000000000..706e9b905
--- /dev/null
+++ b/src/org/traccar/events/OverspeedEventHandler.java
@@ -0,0 +1,79 @@
+package org.traccar.events;
+
+import java.sql.SQLException;
+
+import org.traccar.BaseEventHandler;
+import org.traccar.Context;
+import org.traccar.model.Event;
+import org.traccar.model.Position;
+import org.traccar.model.Server;
+import org.traccar.helper.Log;
+//import org.traccar.model.Device;
+//import org.traccar.model.Group;
+import org.traccar.helper.UnitsConverter;
+
+public class OverspeedEventHandler extends BaseEventHandler {
+
+ private double globalSpeedLimit;
+ private long suppressRepeated;
+
+ public OverspeedEventHandler() {
+ globalSpeedLimit = Context.getConfig().getInteger("event.globalspeedlimit", 0);
+ suppressRepeated = Context.getConfig().getLong("event.suppressrepeated", 60);
+ try {
+ Server server = Context.getDataManager().getServer();
+ String speedUnit = server.getSpeedUnit();
+ if (speedUnit != null) {
+ switch (speedUnit) {
+ case "kmh" : globalSpeedLimit = UnitsConverter.knotsFromKph(globalSpeedLimit);
+ break;
+ case "mph" : globalSpeedLimit = UnitsConverter.knotsFromMph(globalSpeedLimit);
+ default : break;
+ }
+ }
+ } catch (SQLException error) {
+ Log.warning(error);
+ }
+
+ }
+
+ @Override
+ protected Event analizePosition(Position position) {
+ Event event = null;
+ if (!isLastPosition()) {
+ return event;
+ }
+ double speed = position.getSpeed();
+ boolean valid = position.getValid();
+ double deviceSpeedLimit = 0;
+ double groupSpeedLimit = 0;
+// Device device = Context.getIdentityManager().getDeviceById(position.getDeviceId());
+// if (device != null) {
+// deviceSpeedLimit = device.getSpeedLimit();
+// try {
+// Group group = Context.getDataManager().getGroupById(device.getGroupId());
+// if (group != null) {
+// groupSpeedLimit = group.getSpeedLimit();
+// }
+// } catch (SQLException error) {
+// Log.warning(error);
+// }
+// }
+
+ if (valid && globalSpeedLimit != 0 && speed > globalSpeedLimit
+ || valid && groupSpeedLimit != 0 && speed > groupSpeedLimit
+ || valid && deviceSpeedLimit != 0 && speed > deviceSpeedLimit) {
+ try {
+ if (Context.getDataManager().getLastEvents(
+ position.getDeviceId(), Event.DEVICE_OVERSPEED, suppressRepeated).isEmpty()) {
+ event = new Event(Event.DEVICE_OVERSPEED, position.getDeviceId(), position.getId());
+ }
+ } catch (SQLException error) {
+ Log.warning(error);
+ }
+
+ }
+ return event;
+ }
+
+}
diff --git a/src/org/traccar/model/Device.java b/src/org/traccar/model/Device.java
index 934e753b1..d32f9f851 100644
--- a/src/org/traccar/model/Device.java
+++ b/src/org/traccar/model/Device.java
@@ -101,4 +101,17 @@ public class Device {
this.groupId = groupId;
}
+ public static final String STATUS_MOVING = "moving";
+ public static final String STATUS_STOPPED = "stopped";
+
+ private String motion;
+
+ public String getMotion() {
+ return motion;
+ }
+
+ public void setMotion(String motion) {
+ this.motion = motion;
+ }
+
}
diff --git a/src/org/traccar/model/Event.java b/src/org/traccar/model/Event.java
new file mode 100644
index 000000000..27c750c49
--- /dev/null
+++ b/src/org/traccar/model/Event.java
@@ -0,0 +1,74 @@
+package org.traccar.model;
+
+import java.util.Date;
+
+public class Event extends Message {
+
+ public Event(String type, long deviceId, long positionId) {
+ this.setType(type);
+ this.setDeviceId(deviceId);
+ this.setPositionId(positionId);
+ this.eventTime = new Date();
+ }
+
+ public Event(String type, long deviceId) {
+ this.setType(type);
+ this.setDeviceId(deviceId);
+ this.eventTime = new Date();
+ }
+
+ public Event() {
+ }
+
+ private long id;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public static final String COMMAND_RESULT = "command-result";
+
+ public static final String DEVICE_ONLINE = "device-online";
+ public static final String DEVICE_OFFLINE = "device-offline";
+
+ public static final String DEVICE_MOVING = "device-moving";
+ public static final String DEVICE_STOPPED = "device-stopped";
+
+ public static final String DEVICE_OVERSPEED = "device-overspeed";
+
+ public static final String GEOFENCE_ENTER = "geofence-enter";
+ public static final String GEOFENCE_EXIT = "geofence-exit";
+
+ private Date eventTime;
+
+ public Date getEventTime() {
+ if (eventTime != null) {
+ return new Date(eventTime.getTime());
+ } else {
+ return null;
+ }
+ }
+
+ public void setEventTime(Date eventTime) {
+ if (eventTime != null) {
+ this.eventTime = new Date(eventTime.getTime());
+ } else {
+ this.eventTime = null;
+ }
+ }
+
+ private long positionId;
+
+ public long getPositionId() {
+ return positionId;
+ }
+
+ public void setPositionId(long positionId) {
+ this.positionId = positionId;
+ }
+
+}
diff --git a/src/org/traccar/web/WebServer.java b/src/org/traccar/web/WebServer.java
index 8144af0b6..751db7a33 100644
--- a/src/org/traccar/web/WebServer.java
+++ b/src/org/traccar/web/WebServer.java
@@ -44,6 +44,7 @@ import org.traccar.api.resource.GroupResource;
import org.traccar.api.resource.DeviceResource;
import org.traccar.api.resource.PositionResource;
import org.traccar.api.resource.CommandTypeResource;
+import org.traccar.api.resource.EventResource;
import org.traccar.helper.Log;
import javax.naming.InitialContext;
@@ -148,7 +149,8 @@ public class WebServer {
resourceConfig.register(CorsResponseFilter.class);
resourceConfig.registerClasses(ServerResource.class, SessionResource.class, CommandResource.class,
GroupPermissionResource.class, DevicePermissionResource.class, UserResource.class,
- GroupResource.class, DeviceResource.class, PositionResource.class, CommandTypeResource.class);
+ GroupResource.class, DeviceResource.class, PositionResource.class,
+ CommandTypeResource.class, EventResource.class);
servletHandler.addServlet(new ServletHolder(new ServletContainer(resourceConfig)), "/*");
handlers.addHandler(servletHandler);