aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2014-09-03 00:09:42 +1200
committerAnton Tananaev <anton.tananaev@gmail.com>2014-09-03 00:09:42 +1200
commit66b62de750e75e1081ac8eeccca17f11b297d01a (patch)
tree080e3748138f31e5dd8ab9fba6a61993256acb27 /src
parent1f56f881365fbe31736c26c3b5ba848c2fda4f64 (diff)
downloadtraccar-server-66b62de750e75e1081ac8eeccca17f11b297d01a.tar.gz
traccar-server-66b62de750e75e1081ac8eeccca17f11b297d01a.tar.bz2
traccar-server-66b62de750e75e1081ac8eeccca17f11b297d01a.zip
Implement position filtering (fix #259)
Diffstat (limited to 'src')
-rw-r--r--src/org/traccar/BasePipelineFactory.java22
-rw-r--r--src/org/traccar/FilterHandler.java133
-rw-r--r--src/org/traccar/helper/DistanceCalculator.java33
3 files changed, 181 insertions, 7 deletions
diff --git a/src/org/traccar/BasePipelineFactory.java b/src/org/traccar/BasePipelineFactory.java
index d7fcfe28a..e1f1e10e5 100644
--- a/src/org/traccar/BasePipelineFactory.java
+++ b/src/org/traccar/BasePipelineFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2013 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2012 - 2014 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
*/
package org.traccar;
-import java.net.InetAddress;
import java.net.InetSocketAddress;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
@@ -31,18 +30,19 @@ import org.traccar.model.DataManager;
*/
public abstract class BasePipelineFactory implements ChannelPipelineFactory {
- private TrackerServer server;
- private DataManager dataManager;
- private Boolean loggerEnabled;
+ private final TrackerServer server;
+ private final DataManager dataManager;
+ private final Boolean loggerEnabled;
+ private final ReverseGeocoder reverseGeocoder;
+ private FilterHandler filterHandler;
private Integer resetDelay;
- private ReverseGeocoder reverseGeocoder;
/**
* Open channel handler
*/
protected class OpenChannelHandler extends SimpleChannelHandler {
- private TrackerServer server;
+ private final TrackerServer server;
public OpenChannelHandler(TrackerServer server) {
this.server = server;
@@ -95,6 +95,11 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
if (resetDelayProperty != null) {
resetDelay = Integer.valueOf(resetDelayProperty);
}
+
+ String enableFilter = serverManager.getProperties().getProperty("filter.enable");
+ if (enableFilter != null && Boolean.valueOf(enableFilter)) {
+ filterHandler = new FilterHandler(serverManager);
+ }
}
protected DataManager getDataManager() {
@@ -114,6 +119,9 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory {
pipeline.addLast("logger", new StandardLoggingHandler());
}
addSpecificHandlers(pipeline);
+ if (filterHandler != null) {
+ pipeline.addLast("filter", filterHandler);
+ }
if (reverseGeocoder != null) {
pipeline.addLast("geocoder", new ReverseGeocoderHandler(reverseGeocoder));
}
diff --git a/src/org/traccar/FilterHandler.java b/src/org/traccar/FilterHandler.java
new file mode 100644
index 000000000..18ae2ecae
--- /dev/null
+++ b/src/org/traccar/FilterHandler.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2014 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * 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;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.handler.codec.oneone.OneToOneDecoder;
+import org.traccar.helper.DistanceCalculator;
+import org.traccar.helper.Log;
+import org.traccar.model.Position;
+
+public class FilterHandler extends OneToOneDecoder {
+
+ private boolean filterInvalid;
+ private boolean filterZero;
+ private boolean filterDuplicate;
+ private int filterDistance;
+
+ private final Map<Long, Position> lastPositions = new HashMap<Long, Position>();
+
+ public FilterHandler(ServerManager serverManager) {
+ Properties properties = serverManager.getProperties();
+
+ String value = properties.getProperty("filter.invalid");
+ if (value != null) filterInvalid = Boolean.valueOf(value);
+
+ value = properties.getProperty("filter.zero");
+ if (value != null) filterZero = Boolean.valueOf(value);
+
+ value = properties.getProperty("filter.duplicate");
+ if (value != null) filterDuplicate = Boolean.valueOf(value);
+
+ value = properties.getProperty("filter.distance");
+ if (value != null) filterDistance = Integer.valueOf(value);
+ }
+
+ private boolean filterInvalid(Position position) {
+ return filterInvalid && !position.getValid();
+ }
+
+ private boolean filterZero(Position position) {
+ return filterZero &&
+ (position.getLatitude() == 0.0) &&
+ (position.getLongitude() == 0.0);
+ }
+
+ private boolean filterDuplicate(Position position) {
+ if (filterDuplicate) {
+ Position last = lastPositions.get(position.getDeviceId());
+ if (last != null) {
+ return position.getTime().equals(last.getTime());
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ private boolean filterDistance(Position position) {
+ if (filterDistance != 0) {
+ Position last = lastPositions.get(position.getDeviceId());
+ if (last != null) {
+ double distance = DistanceCalculator.distance(
+ position.getLatitude(), position.getLongitude(),
+ last.getLatitude(), last.getLongitude());
+ return distance < filterDistance;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ private boolean filter(Position p) {
+
+ boolean result =
+ filterInvalid(p) ||
+ filterZero(p) ||
+ filterDuplicate(p) ||
+ filterDistance(p);
+
+ if (!result) {
+ lastPositions.put(p.getDeviceId(), p);
+ } else {
+ StringBuilder s = new StringBuilder();
+ Log.info("Position filtered from " + p.getDeviceId());
+ }
+
+ return result;
+ }
+
+ @Override
+ protected Object decode(
+ ChannelHandlerContext ctx, Channel channel, Object msg)
+ throws Exception {
+
+ if (msg instanceof Position) {
+ if (filter((Position) msg)) {
+ return null;
+ }
+ } else if (msg instanceof List) {
+ Iterator<Position> i = ((List<Position>) msg).iterator();
+ while (i.hasNext()) {
+ if (filter(i.next())) {
+ i.remove();
+ }
+ }
+ }
+
+ return msg;
+ }
+
+}
diff --git a/src/org/traccar/helper/DistanceCalculator.java b/src/org/traccar/helper/DistanceCalculator.java
new file mode 100644
index 000000000..072f3d7a8
--- /dev/null
+++ b/src/org/traccar/helper/DistanceCalculator.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * 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.helper;
+
+public class DistanceCalculator {
+
+ private static final double equatorialEarthRadius = 6378.1370D;
+ private static final double deg2rad = (Math.PI / 180);
+
+ public static double distance(double lat1, double lon1, double lat2, double lon2) {
+ double dlong = (lon2 - lon1) * deg2rad;
+ double dlat = (lat2 - lat1) * deg2rad;
+ double a = Math.pow(Math.sin(dlat / 2), 2) +
+ Math.cos(lat1 * deg2rad) * Math.cos(lat2 * deg2rad) * Math.pow(Math.sin(dlong / 2), 2);
+ double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+ double d = equatorialEarthRadius * c;
+ return d * 1000;
+ }
+
+}