dk.dma.ais.packet.AisPacketFiltersStateful.java Source code

Java tutorial

Introduction

Here is the source code for dk.dma.ais.packet.AisPacketFiltersStateful.java

Source

/* Copyright (c) 2011 Danish Maritime Authority.
 *
 * 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 dk.dma.ais.packet;

import dk.dma.ais.message.AisMessage;
import dk.dma.ais.message.AisMessage5;
import dk.dma.ais.message.AisPosition;
import dk.dma.ais.message.AisPositionMessage;
import dk.dma.ais.tracker.targetTracker.TargetInfo;
import dk.dma.ais.tracker.targetTracker.TargetTracker;
import dk.dma.enav.model.geometry.Area;
import org.apache.commons.lang3.ArrayUtils;

import java.util.Arrays;
import java.util.function.Predicate;

import static java.util.Objects.requireNonNull;

/**
 * This class provides factory methods to create Predicate<AisPacket> functions which can be used to filter AisPackets.
 *
 * As opposed to the AisPacketFilters class, this class is designed to create predicates which "remember" some state of AisPackets
 * that have previously been served. This implies, that it is possible to establish more advanced filtering, than just inspecting
 * the current AisPacket.
 *
 * Instead, with this stateful filter, it is possible to generate Predicates which can e.g. filter away AisStaticCommon packages for
 * targets whose position is outside some defined area.
 *
 * @author Thomas Borg Salling <tbsalling@tbsalling.dk>
 * @since v2.1
 */
public class AisPacketFiltersStateful extends AisPacketFiltersBase {

    private AisPacketStream aisPacketStream = new AisPacketStreamImpl();
    private TargetTracker targetTracker = new TargetTracker();

    public AisPacketFiltersStateful() {
        targetTracker.subscribeToPacketStream(aisPacketStream);
    }

    // --- IMO

    /**
     * Return false if this message is known to be related to a target with an IMO no. different to 'imo'.
     * 
     * @param operator
     * @param rhsImo
     * @return
     */

    public Predicate<AisPacket> filterOnTargetImo(final CompareToOperator operator, Integer rhsImo) {
        final int imo = rhsImo;
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final int lhsImo = getImo(mmsi); // Extract IMO no. - if we know it
                return lhsImo < 0 ? false : compare(lhsImo, imo, operator);
            }

            public String toString() {
                return "imo = " + imo;
            }
        };
    }

    /**
     * Return false if this message is known to be related to a target with an IMO outside the given range.
     */

    public Predicate<AisPacket> filterOnTargetImo(final int min, final int max) {
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final int imo = getImo(mmsi); // Extract IMO no. - if we know it
                return imo < 0 ? false : inRange(min, max, imo);
            }

            public String toString() {
                return "imo in " + min + ".." + max;
            }
        };
    }

    /**
     * Return false if this message is known to be related to a target with an IMO outside the given list.
     */

    public Predicate<AisPacket> filterOnTargetImo(Integer[] imos) {
        final int[] list = ArrayUtils.toPrimitive(imos);
        Arrays.sort(list);
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final int imo = getImo(mmsi); // Extract IMO no. - if we know it
                return imo < 0 ? false : Arrays.binarySearch(list, imo) >= 0;
            }

            public String toString() {
                return "imo in " + skipBrackets(Arrays.toString(list));
            }
        };
    }

    // --- ship type

    /**
     * Return false if this message is known to be related to a target with an IMO no. different to 'imo'.
     * 
     * @param operator
     * @param rhsShiptype
     * @return
     */

    public Predicate<AisPacket> filterOnTargetShiptype(final CompareToOperator operator, Integer rhsShiptype) {
        final int shiptype = rhsShiptype;
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final int lhsShiptype = getShiptype(mmsi); // Extract shiptype - if we know it
                return lhsShiptype < 0 ? false : compare(lhsShiptype, shiptype, operator);
            }

            public String toString() {
                return "shiptype = " + shiptype;
            }
        };
    }

    /**
     * Return false if this message is known to be related to a target with an shiptype outside the given range.
     */

    public Predicate<AisPacket> filterOnTargetShiptype(final int min, final int max) {
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final int shiptype = getShiptype(mmsi); // Extract IMO no. - if we know it
                return shiptype < 0 ? false : inRange(min, max, shiptype);
            }

            public String toString() {
                return "imo in " + min + ".." + max;
            }
        };
    }

    /**
     * Return false if this message is known to be related to a target with a ship type outside the given list.
     */

    public Predicate<AisPacket> filterOnTargetShiptype(Integer[] shiptypes) {
        final int[] list = ArrayUtils.toPrimitive(shiptypes);
        Arrays.sort(list);
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final int shiptype = getShiptype(mmsi); // Extract shiptype no. - if we know it
                return shiptype < 0 ? false : Arrays.binarySearch(list, shiptype) >= 0;
            }

            public String toString() {
                return "shiptype in " + skipBrackets(Arrays.toString(list));
            }
        };
    }

    // --- navstat

    /**
     * Return false if this message is known to be related to a target with an navstat different to the rhs parameter.
     * 
     * @param operator
     * @param rhsNavstat
     * @return
     */

    public Predicate<AisPacket> filterOnTargetNavigationalStatus(final CompareToOperator operator,
            Integer rhsNavstat) {
        final int navstat = rhsNavstat;
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final int lhsNavstat = getNavstat(mmsi); // Extract navstat - if we know it
                return lhsNavstat < 0 ? false : compare(lhsNavstat, navstat, operator);
            }

            public String toString() {
                return "navstat = " + navstat;
            }
        };
    }

    /**
     * Return false if this message is known to be related to a target with a navstat outside the given range.
     */

    public Predicate<AisPacket> filterOnTargetNavigationalStatus(final int min, final int max) {
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final int navstat = getNavstat(mmsi); // Extract IMO no. - if we know it
                return navstat < 0 ? false : inRange(min, max, navstat);
            }

            public String toString() {
                return "imo in " + min + ".." + max;
            }
        };
    }

    /**
     * Return false if this message is known to be related to a target with a navstat outside the given list.
     */

    public Predicate<AisPacket> filterOnTargetNavigationalStatus(Integer[] navstats) {
        final int[] list = ArrayUtils.toPrimitive(navstats);
        Arrays.sort(list);
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final int navstat = getNavstat(mmsi); // Extract navstat no. - if we know it
                return navstat < 0 ? false : Arrays.binarySearch(list, navstat) >= 0;
            }

            public String toString() {
                return "navstat in " + skipBrackets(Arrays.toString(list));
            }
        };
    }

    // --- sog

    /**
     * Return false if this message is known to be related to a target with a SOG comparing false to 'sog'.
     * 
     * @param operator
     * @param sog
     * @return
     */

    public Predicate<AisPacket> filterOnTargetSpeedOverGround(final CompareToOperator operator, Float sog) {
        final float rhsSog = sog;
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final float lhsSog = getSog(mmsi); // Extract sog - if we know it
                return lhsSog != lhsSog /* NaN */ ? false : compare(lhsSog, rhsSog, operator);
            }

            public String toString() {
                return "sog " + operator + " " + rhsSog;
            }
        };
    }

    /**
     * Return false if this message is known to be related to a target with a SOG outside the given range.
     */

    public Predicate<AisPacket> filterOnTargetSpeedOverGround(final float min, final float max) {
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final float lhsSog = getSog(mmsi); // Extract sog - if we know it
                return lhsSog != lhsSog /* NaN */ ? false : inRange(min, max, lhsSog);
            }

            public String toString() {
                return "sog in " + min + ".." + max;
            }
        };
    }

    // --- cog

    /**
     * Return false if this message is known to be related to a target with a COG comparing false to 'cog'.
     * 
     * @param operator
     * @param cog
     * @return
     */

    public Predicate<AisPacket> filterOnTargetCourseOverGround(final CompareToOperator operator, Float cog) {
        final float rhsCog = cog;
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final float lhsCog = getCog(mmsi); // Extract cog - if we know it
                return lhsCog != lhsCog /* NaN */ ? false : compare(lhsCog, rhsCog, operator);
            }

            public String toString() {
                return "cog " + operator + " " + rhsCog;
            }
        };
    }

    /**
     * Return false if this message is known to be related to a target with a COG outside the given range.
     */

    public Predicate<AisPacket> filterOnTargetCourseOverGround(final float min, final float max) {
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final float lhsCog = getCog(mmsi); // Extract cog - if we know it
                return lhsCog != lhsCog /* NaN */ ? false : inRange(min, max, lhsCog);
            }

            public String toString() {
                return "cog in " + min + ".." + max;
            }
        };
    }

    // --- hdg

    /**
     * Return false if this message is known to be related to a target with a COG comparing false to 'hdg'.
     * 
     * @param operator
     * @param hdg
     * @return
     */

    public Predicate<AisPacket> filterOnTargetTrueHeading(final CompareToOperator operator, Integer hdg) {
        final int rhsHdg = hdg;
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final int lhsHdg = getHdg(mmsi); // Extract hdg - if we know it
                return lhsHdg < 0 ? false : compare(lhsHdg, rhsHdg, operator);
            }

            public String toString() {
                return "hdg " + operator + " " + rhsHdg;
            }
        };
    }

    /**
     * Return false if this message is known to be related to a target with a COG outside the given range.
     */

    public Predicate<AisPacket> filterOnTargetTrueHeading(final int min, final int max) {
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final int lhsHdg = getHdg(mmsi); // Extract cog - if we know it
                return lhsHdg < 0 ? false : inRange(min, max, lhsHdg);
            }

            public String toString() {
                return "hdg in " + min + ".." + max;
            }
        };
    }

    // --- draught

    /**
     * Return false if this message is known to be related to a target with a draught comparing false to 'draught'.
     * 
     * @param operator
     * @param draught
     * @return
     */

    public Predicate<AisPacket> filterOnTargetDraught(final CompareToOperator operator, Float draught) {
        final float rhsDraught = draught;
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final float lhsDraught = getDraught(mmsi); // Extract draught - if we know it
                return lhsDraught != lhsDraught /* NaN */ ? false : compare(lhsDraught, rhsDraught, operator);
            }

            public String toString() {
                return "draught " + operator + " " + rhsDraught;
            }
        };
    }

    /**
     * Return false if this message is known to be related to a target with a draught outside the given range.
     */

    public Predicate<AisPacket> filterOnTargetDraught(final float min, final float max) {
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final float lhsDraught = getDraught(mmsi); // Extract cog - if we know it
                return lhsDraught != lhsDraught /* NaN */ ? false : inRange(min, max, lhsDraught);
            }

            public String toString() {
                return "draught in " + min + ".." + max;
            }
        };
    }

    // --- lat

    /**
     * Return false if this message is known to be related to a target with a latitude comparing false to 'lat'.
     * 
     * @param operator
     * @param lat
     * @return
     */

    public Predicate<AisPacket> filterOnTargetLatitude(final CompareToOperator operator, Float lat) {
        final float rhsLat = lat;
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final float lhsLat = getLatitude(mmsi); // Extract lat - if we know it
                return lhsLat != lhsLat /* NaN */ ? false : compare(lhsLat, rhsLat, operator);
            }

            public String toString() {
                return "lat " + operator + " " + rhsLat;
            }
        };
    }

    /**
     * Return false if this message is known to be related to a target with a latitude outside the given range.
     */

    public Predicate<AisPacket> filterOnTargetLatitude(final float min, final float max) {
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final float lhsLat = getLatitude(mmsi); // Extract - if we know it
                return lhsLat != lhsLat /* NaN */ ? false : inRange(min, max, lhsLat);
            }

            public String toString() {
                return "lat in " + min + ".." + max;
            }
        };
    }

    // --- lon

    /**
     * Return false if this message is known to be related to a target with a longitude comparing false to 'lon'.
     * 
     * @param operator
     * @param lon
     * @return
     */

    public Predicate<AisPacket> filterOnTargetLongitude(final CompareToOperator operator, Float lon) {
        final float rhsLon = lon;
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final float lhsLon = getLongitude(mmsi); // Extract lon - if we know it
                return lhsLon != lhsLon /* NaN */ ? false : compare(lhsLon, rhsLon, operator);
            }

            public String toString() {
                return "lon " + operator + " " + rhsLon;
            }
        };
    }

    /**
     * Return false if this message is known to be related to a target with a longitude outside the given range.
     */

    public Predicate<AisPacket> filterOnTargetLongitude(final float min, final float max) {
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final float lhsLon = getLongitude(mmsi); // Extract cog - if we know it
                return lhsLon != lhsLon /* NaN */ ? false : inRange(min, max, lhsLon);
            }

            public String toString() {
                return "lon in " + min + ".." + max;
            }
        };
    }

    // ---

    /**
     * Return false if this message is known to be related to a target with a name not comparing to rhs parameter.
     * 
     * @return
     */

    public Predicate<AisPacket> filterOnTargetName(final CompareToOperator operator, final String rhsName) {
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final String lhsName = getName(mmsi); // Extract - if we know it
                return lhsName == null ? false : compare(lhsName, rhsName, operator);
            }

            public String toString() {
                return "name " + operator + " " + rhsName;
            }
        };
    }

    /**
     * Return false if this message is known to be related to a target with a name not comparing to rhs parameter.
     * 
     * @return
     */

    public Predicate<AisPacket> filterOnTargetNameMatch(final String pattern) {
        final String glob = preprocessExpressionString(pattern);
        return p -> {
            aisPacketStream.add(p); // Update state
            final int mmsi = getMmsi(p); // Get MMSI in question
            final String lhsName = getName(mmsi); // Extract - if we know it
            return lhsName != null && matchesGlob(preprocessAisString(lhsName), glob);
        };
    }

    // ---

    /**
     * Return false if this message is known to be related to a target with a callsign not comparing to rhs parameter.
     * 
     * @return
     */
    public Predicate<AisPacket> filterOnTargetCallsign(final CompareToOperator operator, final String rhsCallsign) {
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final String lhsCallsign = getCallsign(mmsi); // Extract - if we know it
                return lhsCallsign == null ? false : compare(lhsCallsign, rhsCallsign, operator);
            }

            public String toString() {
                return "cs " + operator + " " + rhsCallsign;
            }
        };
    }

    /**
     * Return false if this message is known to be related to a target with a callsign not comparing to rhs parameter.
     * 
     * @return
     */
    public Predicate<AisPacket> filterOnTargetCallsignMatch(final String pattern) {
        final String glob = preprocessExpressionString(pattern);
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final String callsign = getCallsign(mmsi); // Extract - if we know it
                return callsign == null ? false : matchesGlob(preprocessAisString(callsign), glob);
            }

            public String toString() {
                return "cs ~ " + glob;
            }
        };
    }

    /**
     * Filter on message to have known position inside given area.
     *
     * @param area
     *            The area that the position must reside inside.
     * @return
     */
    public Predicate<AisPacket> filterOnTargetPositionWithin(final Area area) {
        requireNonNull(area);
        return new Predicate<AisPacket>() {
            public boolean test(AisPacket p) {
                aisPacketStream.add(p); // Update state
                final int mmsi = getMmsi(p); // Get MMSI in question
                final AisPosition pos = getPosition(mmsi); // Extract - if we know it
                return (pos == null || pos.getGeoLocation() == null) ? false : area.contains(pos.getGeoLocation());
            }

            public String toString() {
                return "pos within " + area;
            }
        };
    }

    // ---

    /**
     * Extract mmsi no. from AisPacket
     * 
     * @param p
     * @return
     */
    private static int getMmsi(AisPacket p) {
        final AisMessage aisMessage = p.tryGetAisMessage();
        return aisMessage == null ? -1 : aisMessage.getUserId();
    }

    /**
     * Use target tracker to extract IMO no. based on mmsi lookup.
     * 
     * @param mmsi
     * @return
     */
    private int getImo(int mmsi) {
        int imo = -1;
        TargetInfo target = targetTracker.get(mmsi);
        if (target != null) {
            AisPacket[] staticPackets = target.getStaticPackets();
            if (staticPackets.length > 0 && staticPackets[0].tryGetAisMessage() instanceof AisMessage5) {
                imo = (int) ((AisMessage5) staticPackets[0].tryGetAisMessage()).getImo();
            }
        }
        return imo;
    }

    /**
     * Use target tracker to extract speed over ground based on mmsi lookup.
     * 
     * @param mmsi
     * @return
     */
    private float getSog(int mmsi) {
        float sog = Float.NaN;
        TargetInfo target = targetTracker.get(mmsi);
        if (target != null) {
            AisPacket positionPacket = target.getPositionPacket();
            if (positionPacket != null && positionPacket.tryGetAisMessage() instanceof AisPositionMessage) {
                sog = (float) (((AisPositionMessage) positionPacket.tryGetAisMessage()).getSog() / 10.0);
            }
        }
        return sog;
    }

    /**
     * Use target tracker to extract course over ground based on mmsi lookup.
     * 
     * @param mmsi
     * @return
     */
    private float getCog(int mmsi) {
        float cog = Float.NaN;
        TargetInfo target = targetTracker.get(mmsi);
        if (target != null) {
            AisPacket positionPacket = target.getPositionPacket();
            if (positionPacket != null && positionPacket.tryGetAisMessage() instanceof AisPositionMessage) {
                cog = (float) (((AisPositionMessage) positionPacket.tryGetAisMessage()).getCog() / 10.0);
            }
        }
        return cog;
    }

    /**
     * Use target tracker to extract true heading based on mmsi lookup.
     * 
     * @param mmsi
     * @return
     */
    private int getHdg(int mmsi) {
        int hdg = -1;
        TargetInfo target = targetTracker.get(mmsi);
        if (target != null) {
            AisPacket positionPacket = target.getPositionPacket();
            if (positionPacket != null && positionPacket.tryGetAisMessage() instanceof AisPositionMessage) {
                hdg = ((AisPositionMessage) positionPacket.tryGetAisMessage()).getTrueHeading();
            }
        }
        return hdg;
    }

    /**
     * Use target tracker to extract draught based on mmsi lookup.
     * 
     * @param mmsi
     * @return
     */
    private float getDraught(int mmsi) {
        float draught = Float.NaN;
        TargetInfo target = targetTracker.get(mmsi);
        if (target != null) {
            AisPacket[] staticPackets = target.getStaticPackets();
            if (staticPackets.length > 0 && staticPackets[0].tryGetAisMessage() instanceof AisMessage5) {
                draught = (float) (((AisMessage5) staticPackets[0].tryGetAisMessage()).getDraught() / 10.0);
            }
        }
        return draught;
    }

    /**
     * Use target tracker to extract latitude based on mmsi lookup.
     * 
     * @param mmsi
     * @return
     */
    private float getLatitude(int mmsi) {
        float lat = Float.NaN;
        TargetInfo target = targetTracker.get(mmsi);
        if (target != null) {
            AisPacket positionPacket = target.getPositionPacket();
            if (positionPacket != null && positionPacket.tryGetAisMessage() instanceof AisPositionMessage) {
                lat = (float) ((AisPositionMessage) positionPacket.tryGetAisMessage()).getPos().getLatitudeDouble();
            }
        }
        return lat;
    }

    /**
     * Use target tracker to extract latitude based on mmsi lookup.
     * 
     * @param mmsi
     * @return
     */
    private float getLongitude(int mmsi) {
        float lon = Float.NaN;
        TargetInfo target = targetTracker.get(mmsi);
        if (target != null) {
            AisPacket positionPacket = target.getPositionPacket();
            if (positionPacket != null && positionPacket.tryGetAisMessage() instanceof AisPositionMessage) {
                lon = (float) ((AisPositionMessage) positionPacket.tryGetAisMessage()).getPos()
                        .getLongitudeDouble();
            }
        }
        return lon;
    }

    /**
     * Use target tracker to extract position based on mmsi lookup.
     * 
     * @param mmsi
     * @return
     */
    private AisPosition getPosition(int mmsi) {
        AisPosition pos = null;
        TargetInfo target = targetTracker.get(mmsi);
        if (target != null) {
            AisPacket positionPacket = target.getPositionPacket();
            if (positionPacket != null && positionPacket.tryGetAisMessage() instanceof AisPositionMessage) {
                pos = ((AisPositionMessage) positionPacket.tryGetAisMessage()).getPos();
            }
        }
        return pos;
    }

    /**
     * Use target tracker to extract shiptype based on mmsi lookup.
     * 
     * @param mmsi
     * @return
     */
    private int getShiptype(int mmsi) {
        int shiptype = -1;
        TargetInfo target = targetTracker.get(mmsi);
        if (target != null) {
            AisPacket[] staticPackets = target.getStaticPackets();
            if (staticPackets.length > 0 && staticPackets[0].tryGetAisMessage() instanceof AisMessage5) {
                shiptype = ((AisMessage5) staticPackets[0].tryGetAisMessage()).getShipType();
            }
        }
        return shiptype;
    }

    /**
     * Use target tracker to extract shiptype based on mmsi lookup.
     * 
     * @param mmsi
     * @return
     */
    private int getNavstat(int mmsi) {
        int navstat = -1;
        TargetInfo target = targetTracker.get(mmsi);
        if (target != null) {
            AisPacket positionPacket = target.getPositionPacket();
            if (positionPacket != null && positionPacket.tryGetAisMessage() instanceof AisPositionMessage) {
                navstat = ((AisPositionMessage) positionPacket.tryGetAisMessage()).getNavStatus();
            }
        }
        return navstat;
    }

    /**
     * Use target tracker to extract ship name based on mmsi lookup.
     * 
     * @param mmsi
     * @return
     */
    private String getName(int mmsi) {
        String name = null;
        TargetInfo target = targetTracker.get(mmsi);
        if (target != null) {
            AisPacket[] staticPackets = target.getStaticPackets();
            if (staticPackets.length > 0 && staticPackets[0].tryGetAisMessage() instanceof AisMessage5) {
                name = ((AisMessage5) staticPackets[0].tryGetAisMessage()).getName();
            }
        }
        return name;
    }

    /**
     * Use target tracker to extract ship's callsign based on mmsi lookup.
     * 
     * @param mmsi
     * @return
     */
    private String getCallsign(int mmsi) {
        String cs = null;
        TargetInfo target = targetTracker.get(mmsi);
        if (target != null) {
            AisPacket[] staticPackets = target.getStaticPackets();
            if (staticPackets.length > 0 && staticPackets[0].tryGetAisMessage() instanceof AisMessage5) {
                cs = ((AisMessage5) staticPackets[0].tryGetAisMessage()).getCallsign();
            }
        }
        return cs;
    }
}