diff options
-rw-r--r-- | src/org/traccar/BasePipelineFactory.java | 19 | ||||
-rw-r--r-- | src/org/traccar/MainModule.java | 11 | ||||
-rw-r--r-- | src/org/traccar/config/Keys.java | 75 | ||||
-rw-r--r-- | src/org/traccar/processing/FilterHandler.java (renamed from src/org/traccar/FilterHandler.java) | 82 | ||||
-rw-r--r-- | test/org/traccar/FilterHandlerTest.java | 84 | ||||
-rw-r--r-- | test/org/traccar/processing/FilterHandlerTest.java | 88 |
6 files changed, 199 insertions, 160 deletions
diff --git a/src/org/traccar/BasePipelineFactory.java b/src/org/traccar/BasePipelineFactory.java index 4bc41bd55..022eeeffa 100644 --- a/src/org/traccar/BasePipelineFactory.java +++ b/src/org/traccar/BasePipelineFactory.java @@ -31,6 +31,7 @@ import io.netty.channel.socket.DatagramPacket; import io.netty.handler.timeout.IdleStateHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.traccar.config.Keys; import org.traccar.events.CommandResultEventHandler; import org.traccar.events.DriverEventHandler; import org.traccar.events.FuelDropEventHandler; @@ -42,6 +43,7 @@ import org.traccar.events.OverspeedEventHandler; import org.traccar.events.AlertEventHandler; import org.traccar.processing.ComputedAttributesHandler; import org.traccar.processing.CopyAttributesHandler; +import org.traccar.processing.FilterHandler; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -54,7 +56,6 @@ public abstract class BasePipelineFactory extends ChannelInitializer<Channel> { private final TrackerServer server; private int timeout; - private FilterHandler filterHandler; private DistanceHandler distanceHandler; private EngineHoursHandler engineHoursHandler; private RemoteAddressHandler remoteAddressHandler; @@ -199,10 +200,6 @@ public abstract class BasePipelineFactory extends ChannelInitializer<Channel> { remoteAddressHandler = new RemoteAddressHandler(); } - if (Context.getConfig().getBoolean("filter.enable")) { - filterHandler = new FilterHandler(); - } - if (Context.getGeocoder() != null && !Context.getConfig().getBoolean("geocoder.ignorePositions")) { geocoderHandler = new GeocoderHandler( Context.getGeocoder(), @@ -304,7 +301,7 @@ public abstract class BasePipelineFactory extends ChannelInitializer<Channel> { addHandlers( pipeline, - filterHandler, + Main.getInjector().getInstance(FilterHandler.class), geocoderHandler, motionHandler, engineHoursHandler, @@ -332,12 +329,12 @@ public abstract class BasePipelineFactory extends ChannelInitializer<Channel> { } private void addDynamicHandlers(ChannelPipeline pipeline) { - if (Context.getConfig().hasKey("extra.handlers")) { - String[] handlers = Context.getConfig().getString("extra.handlers").split(","); - for (String handler : handlers) { + String handlers = Context.getConfig().getString(Keys.EXTRA_HANDLERS); + if (handlers != null) { + for (String handler : handlers.split(",")) { try { - pipeline.addLast((ChannelHandler) Class.forName(handler).newInstance()); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException error) { + pipeline.addLast((ChannelHandler) Class.forName(handler).getDeclaredConstructor().newInstance()); + } catch (ReflectiveOperationException error) { LOGGER.warn("Dynamic handler error", error); } } diff --git a/src/org/traccar/MainModule.java b/src/org/traccar/MainModule.java index 26bdfcd60..60f774544 100644 --- a/src/org/traccar/MainModule.java +++ b/src/org/traccar/MainModule.java @@ -22,6 +22,7 @@ import com.google.inject.Singleton; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.database.IdentityManager; +import org.traccar.processing.FilterHandler; import javax.ws.rs.client.Client; @@ -49,6 +50,16 @@ public class MainModule extends AbstractModule { @Singleton @Provides + public static FilterHandler provideFilterHandler(Config config) { + if (config.getBoolean(Keys.FILTER_ENABLE)) { + return new FilterHandler(config); + } else { + return null; + } + } + + @Singleton + @Provides public static WebDataHandler provideWebDataHandler( Config config, IdentityManager identityManager, ObjectMapper objectMapper, Client client) { if (config.getBoolean(Keys.FORWARD_ENABLE)) { diff --git a/src/org/traccar/config/Keys.java b/src/org/traccar/config/Keys.java index 51adfbc13..5b26854ed 100644 --- a/src/org/traccar/config/Keys.java +++ b/src/org/traccar/config/Keys.java @@ -17,6 +17,11 @@ package org.traccar.config; public final class Keys { + public static final ConfigKey EXTRA_HANDLERS = new ConfigKey( + "extra.handlers", + String.class, + "List of external handler classes to use in Netty pipeline."); + public static final ConfigKey FORWARD_ENABLE = new ConfigKey( "forward.enable", Boolean.class, @@ -38,6 +43,76 @@ public final class Keys { Boolean.class, "Boolean value to enable forwarding in JSON format."); + public static final ConfigKey FILTER_ENABLE = new ConfigKey( + "filter.enable", + Boolean.class, + "Boolean flag to enable or disable position filtering."); + + public static final ConfigKey FILTER_INVALID = new ConfigKey( + "filter.invalid", + Boolean.class, + "Filter invalid (valid field is set to false) positions."); + + public static final ConfigKey FILTER_ZERO = new ConfigKey( + "filter.zero", + Boolean.class, + "Filter zero coordinates. Zero latitude and longitude are theoretically valid values, but it practice it " + + "usually indicates invalid GPS data."); + + public static final ConfigKey FILTER_DUPLICATE = new ConfigKey( + "filter.duplicate", + Boolean.class, + "Filter duplicate records (duplicates are detected by time value)."); + + public static final ConfigKey FILTER_FUTURE = new ConfigKey( + "filter.future", + Long.class, + "Filter records with fix time in future. The values is specified in seconds. Records that have fix time " + + "more than specified number of seconds later than current server time would be filtered out."); + + public static final ConfigKey FILTER_ACCURACY = new ConfigKey( + "filter.accuracy", + Integer.class, + "Filter positions with accuracy less than specified value in meters."); + + public static final ConfigKey FILTER_APPROXIMATE = new ConfigKey( + "filter.approximate", + Boolean.class, + "Filter cell and wifi locations that are coming from geolocation provider."); + + public static final ConfigKey FILTER_STATIC = new ConfigKey( + "filter.static", + Boolean.class, + "Filter positions with exactly zero speed values."); + + public static final ConfigKey FILTER_DISTANCE = new ConfigKey( + "filter.distance", + Integer.class, + "Filter records by distance. The values is specified in meters. If the new position is less far than this " + + "value from the last one it gets filtered out."); + + public static final ConfigKey FILTER_MAX_SPEED = new ConfigKey( + "filter.maxSpeed", + Integer.class, + "Filter records by Maximum Speed value in knots. Can be used to filter jumps to far locations even if " + + "they're marked as valid. Shouldn't be too low. Start testing with values at about 25000."); + + public static final ConfigKey FILTER_MIN_PERIOD = new ConfigKey( + "filter.minPeriod", + Integer.class, + "Filter position if time from previous position is less than specified value in seconds."); + + public static final ConfigKey FILTER_SKIP_LIMIT = new ConfigKey( + "filter.skipLimit", + Long.class, + "Time limit for the filtering in seconds. If the time difference between last position and a new one is " + + "more than this limit, the new position will not be filtered out."); + + public static final ConfigKey FILTER_SKIP_ATTRIBUTES_ENABLE = new ConfigKey( + "filter.skipAttributes.enable", + Boolean.class, + "Enable attributes skipping. Attribute skipping can be enabled in the config or device attributes"); + private Keys() { } diff --git a/src/org/traccar/FilterHandler.java b/src/org/traccar/processing/FilterHandler.java index 6f2bb0d2e..df62b1e6d 100644 --- a/src/org/traccar/FilterHandler.java +++ b/src/org/traccar/processing/FilterHandler.java @@ -13,12 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.traccar; +package org.traccar.processing; import io.netty.channel.ChannelHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.traccar.BaseDataHandler; +import org.traccar.Context; import org.traccar.config.Config; +import org.traccar.config.Keys; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; @@ -40,70 +43,19 @@ public class FilterHandler extends BaseDataHandler { private long skipLimit; private boolean skipAttributes; - public void setFilterInvalid(boolean filterInvalid) { - this.filterInvalid = filterInvalid; - } - - public void setFilterZero(boolean filterZero) { - this.filterZero = filterZero; - } - - public void setFilterDuplicate(boolean filterDuplicate) { - this.filterDuplicate = filterDuplicate; - } - - public void setFilterFuture(long filterFuture) { - this.filterFuture = filterFuture; - } - - public void setFilterAccuracy(int filterAccuracy) { - this.filterAccuracy = filterAccuracy; - } - - public void setFilterApproximate(boolean filterApproximate) { - this.filterApproximate = filterApproximate; - } - - public void setFilterStatic(boolean filterStatic) { - this.filterStatic = filterStatic; - } - - public void setFilterDistance(int filterDistance) { - this.filterDistance = filterDistance; - } - - public void setFilterMaxSpeed(int filterMaxSpeed) { - this.filterMaxSpeed = filterMaxSpeed; - } - - public void setFilterMinPeriod(int filterMinPeriod) { - this.filterMinPeriod = filterMinPeriod; - } - - public void setSkipLimit(long skipLimit) { - this.skipLimit = skipLimit; - } - - public void setSkipAttributes(boolean skipAttributes) { - this.skipAttributes = skipAttributes; - } - - public FilterHandler() { - Config config = Context.getConfig(); - if (config != null) { - filterInvalid = config.getBoolean("filter.invalid"); - filterZero = config.getBoolean("filter.zero"); - filterDuplicate = config.getBoolean("filter.duplicate"); - filterFuture = config.getLong("filter.future") * 1000; - filterAccuracy = config.getInteger("filter.accuracy"); - filterApproximate = config.getBoolean("filter.approximate"); - filterStatic = config.getBoolean("filter.static"); - filterDistance = config.getInteger("filter.distance"); - filterMaxSpeed = config.getInteger("filter.maxSpeed"); - filterMinPeriod = config.getInteger("filter.minPeriod") * 1000; - skipLimit = config.getLong("filter.skipLimit") * 1000; - skipAttributes = config.getBoolean("filter.skipAttributes.enable"); - } + public FilterHandler(Config config) { + filterInvalid = config.getBoolean(Keys.FILTER_INVALID); + filterZero = config.getBoolean(Keys.FILTER_ZERO); + filterDuplicate = config.getBoolean(Keys.FILTER_DUPLICATE); + filterFuture = config.getLong(Keys.FILTER_FUTURE) * 1000; + filterAccuracy = config.getInteger(Keys.FILTER_ACCURACY); + filterApproximate = config.getBoolean(Keys.FILTER_APPROXIMATE); + filterStatic = config.getBoolean(Keys.FILTER_STATIC); + filterDistance = config.getInteger(Keys.FILTER_DISTANCE); + filterMaxSpeed = config.getInteger(Keys.FILTER_MAX_SPEED); + filterMinPeriod = config.getInteger(Keys.FILTER_MIN_PERIOD) * 1000; + skipLimit = config.getLong(Keys.FILTER_SKIP_LIMIT) * 1000; + skipAttributes = config.getBoolean(Keys.FILTER_SKIP_ATTRIBUTES_ENABLE); } private boolean filterInvalid(Position position) { diff --git a/test/org/traccar/FilterHandlerTest.java b/test/org/traccar/FilterHandlerTest.java deleted file mode 100644 index 818583eb7..000000000 --- a/test/org/traccar/FilterHandlerTest.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.traccar; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.traccar.model.Position; - -import java.util.Date; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -public class FilterHandlerTest extends BaseTest { - - private FilterHandler filtingHandler; - private FilterHandler passingHandler; - - @Before - public void setUp() { - passingHandler = new FilterHandler(); - filtingHandler = new FilterHandler(); - filtingHandler.setFilterInvalid(true); - filtingHandler.setFilterZero(true); - filtingHandler.setFilterDuplicate(true); - filtingHandler.setFilterFuture(5 * 60); - filtingHandler.setFilterApproximate(true); - filtingHandler.setFilterStatic(true); - filtingHandler.setFilterDistance(10); - filtingHandler.setFilterMaxSpeed(500); - filtingHandler.setSkipLimit(10); - } - - @After - public void tearDown() { - filtingHandler = null; - passingHandler = null; - } - - private Position createPosition( - long deviceId, - Date time, - boolean valid, - double latitude, - double longitude, - double altitude, - double speed, - double course) { - - Position p = new Position(); - p.setDeviceId(deviceId); - p.setTime(time); - p.setValid(valid); - p.setLatitude(latitude); - p.setLongitude(longitude); - p.setAltitude(altitude); - p.setSpeed(speed); - p.setCourse(course); - return p; - } - - @Test - public void testFilterInvalid() throws Exception { - - Position position = createPosition(0, new Date(), true, 10, 10, 10, 10, 10); - - assertNotNull(filtingHandler.handlePosition(position)); - assertNotNull(passingHandler.handlePosition(position)); - - position = createPosition(0, new Date(Long.MAX_VALUE), true, 10, 10, 10, 10, 10); - - assertNull(filtingHandler.handlePosition(position)); - assertNotNull(passingHandler.handlePosition(position)); - - position = createPosition(0, new Date(), false, 10, 10, 10, 10, 10); - - assertNull(filtingHandler.handlePosition(position)); - assertNotNull(passingHandler.handlePosition(position)); - - position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - filtingHandler.setSkipAttributes(true); - assertNotNull(filtingHandler.handlePosition(position)); - } - -} diff --git a/test/org/traccar/processing/FilterHandlerTest.java b/test/org/traccar/processing/FilterHandlerTest.java new file mode 100644 index 000000000..e0e9a9912 --- /dev/null +++ b/test/org/traccar/processing/FilterHandlerTest.java @@ -0,0 +1,88 @@ +package org.traccar.processing; + +import org.junit.Before; +import org.junit.Test; +import org.traccar.BaseTest; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.Position; + +import java.util.Date; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +public class FilterHandlerTest extends BaseTest { + + private FilterHandler passingHandler = new FilterHandler(new Config()); + private FilterHandler filteringHandler; + + @Before + public void before() { + Config config = new Config(); + config.setString(Keys.FILTER_INVALID, String.valueOf(true)); + config.setString(Keys.FILTER_ZERO, String.valueOf(true)); + config.setString(Keys.FILTER_DUPLICATE, String.valueOf(true)); + config.setString(Keys.FILTER_FUTURE, String.valueOf(5 * 60)); + config.setString(Keys.FILTER_APPROXIMATE, String.valueOf(true)); + config.setString(Keys.FILTER_STATIC, String.valueOf(true)); + config.setString(Keys.FILTER_DISTANCE, String.valueOf(10)); + config.setString(Keys.FILTER_MAX_SPEED, String.valueOf(500)); + config.setString(Keys.FILTER_SKIP_LIMIT, String.valueOf(10)); + config.setString(Keys.FILTER_SKIP_ATTRIBUTES_ENABLE, String.valueOf(true)); + filteringHandler = new FilterHandler(config); + } + + private Position createPosition( + long deviceId, + Date time, + boolean valid, + double latitude, + double longitude, + double altitude, + double speed, + double course) { + + Position position = new Position(); + position.setDeviceId(deviceId); + position.setTime(time); + position.setValid(valid); + position.setLatitude(latitude); + position.setLongitude(longitude); + position.setAltitude(altitude); + position.setSpeed(speed); + position.setCourse(course); + return position; + } + + @Test + public void testFilter() { + + Position position = createPosition(0, new Date(), true, 10, 10, 10, 10, 10); + + assertNotNull(filteringHandler.handlePosition(position)); + assertNotNull(passingHandler.handlePosition(position)); + + position = createPosition(0, new Date(Long.MAX_VALUE), true, 10, 10, 10, 10, 10); + + assertNull(filteringHandler.handlePosition(position)); + assertNotNull(passingHandler.handlePosition(position)); + + position = createPosition(0, new Date(), false, 10, 10, 10, 10, 10); + + assertNull(filteringHandler.handlePosition(position)); + assertNotNull(passingHandler.handlePosition(position)); + + } + + @Test + public void testSkipAttributes() { + + Position position = createPosition(0, new Date(), false, 10, 10, 10, 10, 10); + position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); + + assertNotNull(filteringHandler.handlePosition(position)); + + } + +} |