From 180447bae8000a6ab083cb9022e8421e45320c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kozio=C5=82?= Date: Sun, 8 Apr 2018 18:40:59 +0200 Subject: [PATCH 1/4] Implement BitVector.toString(). --- .../java/net/sf/marineapi/ais/util/BitVector.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/sf/marineapi/ais/util/BitVector.java b/src/main/java/net/sf/marineapi/ais/util/BitVector.java index 12cd9100..607aa6c1 100644 --- a/src/main/java/net/sf/marineapi/ais/util/BitVector.java +++ b/src/main/java/net/sf/marineapi/ais/util/BitVector.java @@ -45,9 +45,15 @@ public BitVector(BitSet vector, int bits) { } public void dump() { - for(int i = 0; i < fLength; i++) - System.out.print(fBitVector.get(i) ? 1 : 0); - System.out.print("\n"); + System.out.println(this); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(fLength); + for (int i = 0; i < fLength; i++) + sb.append(fBitVector.get(i) ? '1' : '0'); + return sb.toString(); } public void set(int index) { From fed6f97f622ea8fb5b6c338bdf51573b9c2894ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kozio=C5=82?= Date: Sun, 8 Apr 2018 19:04:20 +0200 Subject: [PATCH 2/4] Refactor AISMessageFactory to use more flexible parser creation. --- .../ais/parser/AISMessageFactory.java | 42 ++++-------- .../ais/parser/AISMessageParserFactory.java | 53 +++++++++++++++ .../parser/MapBasedLegacyParserFactory.java | 67 +++++++++++++++++++ 3 files changed, 133 insertions(+), 29 deletions(-) create mode 100644 src/main/java/net/sf/marineapi/ais/parser/AISMessageParserFactory.java create mode 100644 src/main/java/net/sf/marineapi/ais/parser/MapBasedLegacyParserFactory.java diff --git a/src/main/java/net/sf/marineapi/ais/parser/AISMessageFactory.java b/src/main/java/net/sf/marineapi/ais/parser/AISMessageFactory.java index d2deb515..942d3816 100644 --- a/src/main/java/net/sf/marineapi/ais/parser/AISMessageFactory.java +++ b/src/main/java/net/sf/marineapi/ais/parser/AISMessageFactory.java @@ -20,12 +20,10 @@ */ package net.sf.marineapi.ais.parser; -import java.lang.reflect.Constructor; -import java.util.HashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; import net.sf.marineapi.ais.message.AISMessage; -import net.sf.marineapi.ais.util.Sixbit; import net.sf.marineapi.nmea.sentence.AISSentence; /** @@ -36,23 +34,16 @@ public class AISMessageFactory { private static AISMessageFactory instance; - private Map> parsers; + private List parserFactories; /** * Hidden constructor. */ private AISMessageFactory() { - parsers = new HashMap>(7); - parsers.put(1, AISMessage01Parser.class); - parsers.put(2, AISMessage02Parser.class); - parsers.put(3, AISMessage03Parser.class); - parsers.put(4, AISMessage04Parser.class); - parsers.put(5, AISMessage05Parser.class); - parsers.put(9, AISMessage09Parser.class); - parsers.put(18, AISMessage18Parser.class); - parsers.put(19, AISMessage19Parser.class); - parsers.put(21, AISMessage21Parser.class); - parsers.put(24, AISMessage24Parser.class); + parserFactories = new ArrayList<>(); + parserFactories.add(new MapBasedLegacyParserFactory()); + parserFactories.add(new AISMessage08DAC200FID10Parser.Factory()); + parserFactories.add(new AISMessage08Parser.Factory()); } @@ -70,21 +61,14 @@ public AISMessage create(AISSentence... sentences) { AISMessageParser parser = new AISMessageParser(sentences); - if (!parsers.containsKey(parser.getMessageType())) { - String msg = String.format("no parser for message type %d", parser.getMessageType()); - throw new IllegalArgumentException(msg); + for (AISMessageParserFactory parserFactory : parserFactories) { + if (parserFactory.canCreate(parser)) { + return parserFactory.create(parser); + } } - AISMessage result; - Class c = parsers.get(parser.getMessageType()); - try { - Constructor co = c.getConstructor(Sixbit.class); - result = co.newInstance(parser.getSixbit()); - } catch (Exception e) { - throw new IllegalStateException(e.getCause()); - } - - return result; + String msg = String.format("no parser for message type %d", parser.getMessageType()); + throw new IllegalArgumentException(msg); } /** diff --git a/src/main/java/net/sf/marineapi/ais/parser/AISMessageParserFactory.java b/src/main/java/net/sf/marineapi/ais/parser/AISMessageParserFactory.java new file mode 100644 index 00000000..ef25d025 --- /dev/null +++ b/src/main/java/net/sf/marineapi/ais/parser/AISMessageParserFactory.java @@ -0,0 +1,53 @@ +/* + * AISMessageParserFactory.java + * Copyright (C) 2018 Paweł Kozioł + * + * This file is part of Java Marine API. + * + * + * Java Marine API is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Java Marine API is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Java Marine API. If not, see . + */ +package net.sf.marineapi.ais.parser; + +import net.sf.marineapi.ais.message.AISMessage; + +/** + * Internal interface used by {@link AISMessageFactory} + * to find and create concrete AIS message parsers. + * + * @author Paweł Kozioł + */ +interface AISMessageParserFactory { + + /** + * Invoked before {@link #create(AISMessageParser)} to determine if factory + * is able to create parser from partially-parsed message. + * + * @param parser Partially-parsed message + * @return {@code true} when factory can create parser, + * {@code false} otherwise. + */ + boolean canCreate(AISMessageParser parser); + + /** + * Creates new message parser from given partially-parsed message. + * Have to be called only if {@link #canCreate(AISMessageParser)} returned {@code true}. + * + * @param parser Partially-parsed message + * @throws IllegalStateException If message parser cannot be constructed + * due to illegal state, e.g. invalid or empty message. + * @return Instance of AISMessageParser + */ + AISMessage create(AISMessageParser parser); +} diff --git a/src/main/java/net/sf/marineapi/ais/parser/MapBasedLegacyParserFactory.java b/src/main/java/net/sf/marineapi/ais/parser/MapBasedLegacyParserFactory.java new file mode 100644 index 00000000..68c2d902 --- /dev/null +++ b/src/main/java/net/sf/marineapi/ais/parser/MapBasedLegacyParserFactory.java @@ -0,0 +1,67 @@ +/* + * MapBasedLegacyParserFactory.java + * Copyright (C) 2015 Kimmo Tuukkanen + * + * This file is part of Java Marine API. + * + * + * Java Marine API is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Java Marine API is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Java Marine API. If not, see . + */ +package net.sf.marineapi.ais.parser; + +import net.sf.marineapi.ais.message.AISMessage; +import net.sf.marineapi.ais.util.Sixbit; + +import java.lang.reflect.Constructor; +import java.util.HashMap; +import java.util.Map; + +/** + * Implementation of AISMessageParserFactory extracted from AISMessageFactory, + * that uses reflection to create AISMessages based on MessageType. + */ +class MapBasedLegacyParserFactory implements AISMessageParserFactory { + + private Map> parsers; + + MapBasedLegacyParserFactory() { + parsers = new HashMap<>(10); + parsers.put(1, AISMessage01Parser.class); + parsers.put(2, AISMessage02Parser.class); + parsers.put(3, AISMessage03Parser.class); + parsers.put(4, AISMessage04Parser.class); + parsers.put(5, AISMessage05Parser.class); + parsers.put(9, AISMessage09Parser.class); + parsers.put(18, AISMessage18Parser.class); + parsers.put(19, AISMessage19Parser.class); + parsers.put(21, AISMessage21Parser.class); + parsers.put(24, AISMessage24Parser.class); + } + + @Override + public boolean canCreate(AISMessageParser parser) { + return parsers.containsKey(parser.getMessageType()); + } + + @Override + public AISMessage create(AISMessageParser parser) { + try { + Class c = parsers.get(parser.getMessageType()); + Constructor co = c.getConstructor(Sixbit.class); + return co.newInstance(parser.getSixbit()); + } catch (Exception e) { + throw new IllegalStateException(e.getCause()); + } + } +} From 71dd7180940da664e2ab179980c019be6b60ef69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kozio=C5=82?= Date: Sun, 8 Apr 2018 19:32:49 +0200 Subject: [PATCH 3/4] Implemented parser for AIS Message 8: Binary Broadcast Message. --- .../marineapi/ais/message/AISMessage08.java | 54 +++++++++ .../ais/parser/AISMessage08Parser.java | 112 ++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 src/main/java/net/sf/marineapi/ais/message/AISMessage08.java create mode 100644 src/main/java/net/sf/marineapi/ais/parser/AISMessage08Parser.java diff --git a/src/main/java/net/sf/marineapi/ais/message/AISMessage08.java b/src/main/java/net/sf/marineapi/ais/message/AISMessage08.java new file mode 100644 index 00000000..adc42fac --- /dev/null +++ b/src/main/java/net/sf/marineapi/ais/message/AISMessage08.java @@ -0,0 +1,54 @@ +/* + * AISMessage08.java + * Copyright (C) 2018 Paweł Kozioł + * + * This file is part of Java Marine API. + * + * + * Java Marine API is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Java Marine API is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Java Marine API. If not, see . + */ +package net.sf.marineapi.ais.message; + +import net.sf.marineapi.ais.util.BitVector; + +/** + * Binary Broadcast Message. + * + * @author Paweł Kozioł + */ +public interface AISMessage08 extends AISMessage { + + /** + * Returns Designated Area Code used with FID to determine message subtype. + * + * @return Designated Area Code + */ + int getDAC(); + + /** + * Returns Functional ID used with DAC to determine message subtype. + * + * @return Functional ID + */ + int getFID(); + + /** + * Returns message binary data. + * Useful for debugging when there are no specific implementations + * for given combination of DAC and FID. + * + * @return Binary data with maximum 952 bits. + */ + BitVector getData(); +} diff --git a/src/main/java/net/sf/marineapi/ais/parser/AISMessage08Parser.java b/src/main/java/net/sf/marineapi/ais/parser/AISMessage08Parser.java new file mode 100644 index 00000000..eada5891 --- /dev/null +++ b/src/main/java/net/sf/marineapi/ais/parser/AISMessage08Parser.java @@ -0,0 +1,112 @@ +/* + * AISMessage08Parser.java + * Copyright (C) 2018 Paweł Kozioł + * + * This file is part of Java Marine API. + * + * + * Java Marine API is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Java Marine API is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Java Marine API. If not, see . + */ +package net.sf.marineapi.ais.parser; + +import net.sf.marineapi.ais.message.AISMessage08; +import net.sf.marineapi.ais.util.BitVector; +import net.sf.marineapi.ais.util.Sixbit; + +/** + * AIS Message 8 implementation: Binary Broadcast Message. + * + * Length of data depends on message sub-type (DAC and FID). + * Maximum length is 952 bits. + * + *
+ * Field  Name                                      Bits    (from, to  )
+ * -------------------------------------------------------------------------
+ *  1     messageID                                    6    (   1,    6)
+ *  2     repeatIndicator                              2    (   7,    8)
+ *  3     userID                                      30    (   9,   38)
+ *  4     spare                                        2    (  39,   40)
+ *  5     designatedAreaCode                          10    (  41,   50)
+ *  6     functionalID                                 6    (  51,   56)
+ *  7     data                                       952    (  57, 1008)
+ *                                                  ---- +
+ *                                              sum 1008
+ * 
+ * + * @author Paweł Kozioł + */ +class AISMessage08Parser extends AISMessageParser implements AISMessage08 { + + private final static String SEPARATOR = "\n\t"; + private final static int DAC = 0; + private final static int FID = 1; + private final static int DATA = 2; + private final static int[] FROM = {40, 50, 56}; + private final static int[] TO = {50, 56}; + + public static class Factory implements AISMessageParserFactory { + + @Override + public boolean canCreate(AISMessageParser parser) { + return parser.getMessageType() == 8; + } + + @Override + public AISMessage08Parser create(AISMessageParser parser) { + return new AISMessage08Parser(parser.getSixbit()); + } + + static int getDAC(Sixbit content) { + return content.getInt(FROM[DAC], TO[DAC]); + } + + static int getFID(Sixbit content) { + return content.getInt(FROM[FID], TO[FID]); + } + } + + private int dac; + private int fid; + private BitVector data; + + public AISMessage08Parser(Sixbit content) { + super(content); + + dac = Factory.getDAC(content); + fid = Factory.getFID(content); + data = content.get(FROM[DATA], content.length()); + } + + @Override + public int getDAC() { + return dac; + } + + @Override + public int getFID() { + return fid; + } + + @Override + public BitVector getData() { + return data; + } + + public String toString() { + String result = "\tDAC: " + getDAC(); + result += SEPARATOR + "FID: " + getFID(); + result += SEPARATOR + "Data: " + getData(); + return result; + } +} From c1543ace96a1ca70ea16cd519d24231a4fabc85b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kozio=C5=82?= Date: Sun, 8 Apr 2018 19:55:32 +0200 Subject: [PATCH 4/4] Implemented parser for AIS Message 8 subtype, DAC = 200, FID = 10. --- .../ais/message/AISMessage08DAC200FID10.java | 91 +++++++++ .../parser/AISMessage08DAC200FID10Parser.java | 188 ++++++++++++++++++ 2 files changed, 279 insertions(+) create mode 100644 src/main/java/net/sf/marineapi/ais/message/AISMessage08DAC200FID10.java create mode 100644 src/main/java/net/sf/marineapi/ais/parser/AISMessage08DAC200FID10Parser.java diff --git a/src/main/java/net/sf/marineapi/ais/message/AISMessage08DAC200FID10.java b/src/main/java/net/sf/marineapi/ais/message/AISMessage08DAC200FID10.java new file mode 100644 index 00000000..679b6402 --- /dev/null +++ b/src/main/java/net/sf/marineapi/ais/message/AISMessage08DAC200FID10.java @@ -0,0 +1,91 @@ +/* + * AISMessage08DAC200FID10.java + * Copyright (C) 2018 Paweł Kozioł + * + * This file is part of Java Marine API. + * + * + * Java Marine API is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Java Marine API is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Java Marine API. If not, see . + */ +package net.sf.marineapi.ais.message; + +/** + * Inland ship static and voyage related data (Inland AIS). + * + * @author Paweł Kozioł + */ +public interface AISMessage08DAC200FID10 extends AISMessage08 { + + /** + * Returns European Number of Identification a.k.a. European Vessel Identification Number. + * @return European Number of Identification (8 six-bit characters) + */ + String getENI(); + + /** + * Returns length of the ship in meters with 0.1m precision. + * @return Length of the ship in meters with 0.1m precision + */ + double getShipLength(); + + /** + * Returns beam of the ship in meters with 0.1m precision. + * @return Beam of the ship in meters with 0.1m precision + */ + double getShipBeam(); + + /** + * Returns ship/combination type as full ERI codes with range 8000-8370 + * or ERI SOLAS codes in the range 1-99. + * + * @return Ship/combination type + */ + int getShipType(); + + /** + * Returns hazardous cargo code. + * @return Hazardous cargo code + */ + int getHazardCode(); + + /** + * Returns draught in meters with 0.01m precision. + * @return Draught in meters with 0.01m precision + */ + double getDraught(); + + /** + * Returns load status. 0 = N/A, 1 = Unloaded, 2 = Loaded. + * @return Load status + */ + int getLoadStatus(); + + /** + * Returns speed inf. quality. 0 = low/GNSS (default) 1 = high + * @return Speed inf. quality + */ + boolean getSpeedQuality(); + + /** + * Returns course inf. quality. 0 = low/GNSS (default) 1 = high + * @return Course inf. quality + */ + boolean getCourseQuality(); + + /** + * Returns heading inf. quality. 0 = low/GNSS (default) 1 = high + * @return Heading inf. quality + */ + boolean getHeadingQuality(); +} diff --git a/src/main/java/net/sf/marineapi/ais/parser/AISMessage08DAC200FID10Parser.java b/src/main/java/net/sf/marineapi/ais/parser/AISMessage08DAC200FID10Parser.java new file mode 100644 index 00000000..29dbb2e6 --- /dev/null +++ b/src/main/java/net/sf/marineapi/ais/parser/AISMessage08DAC200FID10Parser.java @@ -0,0 +1,188 @@ +/* + * AISMessage08DAC200FID10Parser.java + * Copyright (C) 2018 Paweł Kozioł + * + * This file is part of Java Marine API. + * + * + * Java Marine API is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Java Marine API is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Java Marine API. If not, see . + */ +package net.sf.marineapi.ais.parser; + +import net.sf.marineapi.ais.message.AISMessage08DAC200FID10; +import net.sf.marineapi.ais.util.Sixbit; + +/** + * AIS Message 8 subtype, DAC = 200, FID = 10: + * Inland ship static and voyage related data (Inland AIS). + * + *
+ * Field  Name                                      Bits    (from, to )
+ * -------------------------------------------------------------------------
+ *  1     messageID                                    6    (   1,   6)
+ *  2     repeatIndicator                              2    (   7,   8)
+ *  3     userID                                      30    (   9,  38)
+ *  4     spare                                        2    (  39,  40)
+ *  5     designatedAreaCode                          10    (  41,  50)
+ *  6     functionalID                                 6    (  51,  56)
+ *  7     European Vessel ID                          48    (  57, 104)
+ *  7     Length of ship                              13    (  58, 117)
+ *  7     Beam of ship                                10    ( 118, 127)
+ *  7     Ship/combination type                       14    ( 128, 141)
+ *  7     Hazardous cargo                              3    ( 142, 144)
+ *  7     Draught                                     11    ( 145, 155)
+ *  7     Loaded/Unloaded                              2    ( 156, 157)
+ *  7     Speed inf. quality                           1    ( 158, 158)
+ *  7     Course inf. quality                          1    ( 159, 159)
+ *  7     Heading inf. quality                         1    ( 160, 160)
+ *  7     spare2                                       8    ( 161, 168)
+ *                                                  ---- +
+ *                                               sum 168
+ * 
+ * + * @author Paweł Kozioł + */ +class AISMessage08DAC200FID10Parser extends AISMessage08Parser implements AISMessage08DAC200FID10 { + + private final static int MSG_TYPE = 8; + private final static int MSG_DAC = 200; + private final static int MSG_FID = 10; + private final static int MSG_LEN = 168; + + private final static String SEPARATOR = "\n\t"; + private final static int VIN = 0; + private final static int SHIP_LENGTH = 1; + private final static int SHIP_BEAM = 2; + private final static int SHIP_TYPE = 3; + private final static int HAZARD_CODE = 4; + private final static int DRAUGHT = 5; + private final static int LOAD_STATUS = 6; + private final static int SPEED_QUALITY = 7; + private final static int COURSE_QUALITY = 8; + private final static int HEADING_QUALITY = 9; + private final static int[] FROM = { + 56, 104, 117, 127, 141, 144, 155, 157, 158, 159}; + private final static int[] TO = { + 104, 117, 127, 141, 144, 155, 157, 158, 159, 160}; + + public static class Factory extends AISMessage08Parser.Factory { + + @Override + public boolean canCreate(AISMessageParser parser) { + return parser.getMessageType() == MSG_TYPE + && parser.getSixbit().length() == MSG_LEN + && getDAC(parser.getSixbit()) == MSG_DAC + && getFID(parser.getSixbit()) == MSG_FID; + } + + @Override + public AISMessage08DAC200FID10Parser create(AISMessageParser parser) { + return new AISMessage08DAC200FID10Parser(parser.getSixbit()); + } + } + + private String vin; + private double shipLength; + private double shipBeam; + private int shipType; + private int hazardCode; + private double draught; + private int loadStatus; + private boolean speedQuality; + private boolean courseQuality; + private boolean headingQuality; + + public AISMessage08DAC200FID10Parser(Sixbit content) { + super(content); + if (content.length() != 168) + throw new IllegalArgumentException("Wrong message length"); + + vin = content.getString(FROM[VIN], TO[VIN]); + shipLength = 0.1 * content.getInt(FROM[SHIP_LENGTH], TO[SHIP_LENGTH]); + shipBeam = 0.1 * content.getInt(FROM[SHIP_BEAM], TO[SHIP_BEAM]); + shipType = content.getInt(FROM[SHIP_TYPE], TO[SHIP_TYPE]); + hazardCode = content.getInt(FROM[HAZARD_CODE], TO[HAZARD_CODE]); + draught = 0.01 * content.getInt(FROM[DRAUGHT], TO[DRAUGHT]); + loadStatus = content.getInt(FROM[LOAD_STATUS], TO[LOAD_STATUS]); + speedQuality = content.getBoolean(FROM[SPEED_QUALITY]); + courseQuality = content.getBoolean(FROM[COURSE_QUALITY]); + headingQuality = content.getBoolean(FROM[HEADING_QUALITY]); + } + + @Override + public String getENI() { + return vin; + } + + @Override + public double getShipLength() { + return shipLength; + } + + @Override + public double getShipBeam() { + return shipBeam; + } + + @Override + public int getShipType() { + return shipType; + } + + @Override + public int getHazardCode() { + return hazardCode; + } + + @Override + public double getDraught() { + return draught; + } + + @Override + public int getLoadStatus() { + return loadStatus; + } + + @Override + public boolean getSpeedQuality() { + return speedQuality; + } + + @Override + public boolean getCourseQuality() { + return courseQuality; + } + + @Override + public boolean getHeadingQuality() { + return headingQuality; + } + + public String toString() { + String result = "\tDAC: " + getDAC(); + result += SEPARATOR + "FID: " + getFID(); + result += SEPARATOR + "VIN: " + getENI(); + result += SEPARATOR + "Ship length: " + getShipLength(); + result += SEPARATOR + "Ship beam: " + getShipBeam(); + result += SEPARATOR + "Ship type: " + getShipType(); + result += SEPARATOR + "Hazard code: " + getHazardCode(); + result += SEPARATOR + "Draught: " + getDraught(); + result += SEPARATOR + "Load status: " + getLoadStatus(); + result += SEPARATOR + "Speed quality: " + (speedQuality ? "high" : "low"); + result += SEPARATOR + "Course quality: " + (courseQuality ? "high" : "low"); + result += SEPARATOR + "Heading quality: " + (headingQuality ? "high" : "low"); + return result; + } +}