View Javadoc
1   package au.gov.amsa.ais;
2   
3   import au.gov.amsa.util.nmea.NmeaMessage;
4   import au.gov.amsa.util.nmea.NmeaUtil;
5   import au.gov.amsa.util.nmea.Talker;
6   
7   /**
8    * Wraps an NMEA line containing an AIS message with accessor methods.
9    * 
10   * @author dxm
11   * 
12   */
13  public class AisNmeaMessage {
14  
15  	private static final AisMessageParser aisParser = new AisMessageParser(
16  	        Util.getAisExtractorFactory());
17  
18  	private final NmeaMessage nmea;
19  
20  	private final String format;
21  
22  	private final int fragmentCount;
23  
24  	private final int fragmentNumber;
25  
26  	private final String sequentialMessageId;
27  
28  	private final String channel;
29  
30  	private final String aisMessage;
31  
32  	private final int padBits;
33  
34  	/**
35  	 * Constructor.
36  	 * 
37  	 * @param line
38  	 *            is an NMEA line containing an AIS message.
39  	 */
40  	public AisNmeaMessage(String line) {
41  		this(NmeaUtil.parseNmea(validateLine(line)));
42  	}
43  	
44  	public static AisNmeaMessage from(String line) {
45  	    return new AisNmeaMessage(line);
46  	}
47  
48  	private static String validateLine(String line) {
49  		try {
50  			if (!NmeaUtil.isValid(line))
51  				throw new AisParseException("invalid checksum: " + line + ", calculated checksum="
52  				        + NmeaUtil.getChecksum(line));
53  			return line;
54  		} catch (RuntimeException e) {
55  			throw new AisParseException(e);
56  		}
57  	}
58  
59  	public AisNmeaMessage(NmeaMessage nmea) {
60  		try {
61  			this.nmea = nmea;
62  			if (nmea.getItems().size() < 7)
63  				throw new AisParseException("ais nmea line must have at least 7 columns:"
64  				        + nmea.getItems());
65  			format = getItem(0);
66  			fragmentCount = Integer.parseInt(getItem(1));
67  			fragmentNumber = Integer.parseInt(getItem(2));
68  			sequentialMessageId = getItem(3);
69  			channel = getItem(4);
70  			aisMessage = getItem(5);
71  			padBits = Integer.parseInt(nmea.getItems().get(6));
72  		} catch (RuntimeException e) {
73  			throw new AisParseException(e);
74  		}
75  	}
76  
77  	/**
78  	 * Returns the tag block unix time value.
79  	 * 
80  	 * @return
81  	 */
82  	public Long getTime() {
83  		return nmea.getUnixTimeMillis();
84  	}
85  
86  	/**
87  	 * Returns the {@link Talker} corresponding to the first two characters of
88  	 * the message format type (e.g. AIVDM -> AI).
89  	 * 
90  	 * @return
91  	 */
92  	public Talker getTalker() {
93  		return nmea.getTalker();
94  	}
95  
96  	/**
97  	 * Returns the checksum field at the end of the NMEA line. Does not
98  	 * <i>calculate</i> the checksum.
99  	 * 
100 	 * @param nmea
101 	 * @return
102 	 */
103 	private static String getChecksum(NmeaMessage nmea) {
104 		return nmea.getChecksum();
105 	}
106 
107 	/**
108 	 * Returns the string at column <code>index</code>, 0 based.
109 	 * 
110 	 * @param index
111 	 * @return
112 	 */
113 	private String getItem(int index) {
114 		return nmea.getItems().get(index);
115 	}
116 
117 	/**
118 	 * Returns the NMEA format (from the first column after the tag block if it
119 	 * exists).
120 	 * 
121 	 * @return
122 	 */
123 	public String getFormat() {
124 		return format;
125 	}
126 
127 	/**
128 	 * Returns the count of fragments.
129 	 * 
130 	 * @return
131 	 */
132 	public int getFragmentCount() {
133 		return fragmentCount;
134 	}
135 
136 	/**
137 	 * Returns the current fragment number.
138 	 * 
139 	 * @return
140 	 */
141 	public int getFragmentNumber() {
142 		return fragmentNumber;
143 	}
144 
145 	/**
146 	 * Returns the sequential message id.
147 	 * 
148 	 * @return
149 	 */
150 	public String getSequentialMessageId() {
151 		return sequentialMessageId;
152 	}
153 
154 	/**
155 	 * Returns the channel.
156 	 * 
157 	 * @return
158 	 */
159 	public String getChannel() {
160 		return channel;
161 	}
162 
163 	public int getPadBits() {
164 		return padBits;
165 	}
166 
167 	/**
168 	 * Returns the parsed contents of column 5 of the AIS NMEA line.
169 	 * 
170 	 * @return
171 	 */
172 	public AisMessage getMessage() {
173 		AisMessage m = aisParser.parse(aisMessage, nmea.getSource(), padBits);
174 		return m;
175 	}
176 
177 	public Timestamped<AisMessage> getTimestampedMessage(long defaultTime) {
178 		Long time = getTime();
179 		if (time == null)
180 			return Timestamped.create(getMessage(), defaultTime);
181 		else
182 			return Timestamped.create(getMessage(), getTime());
183 	}
184 
185 	public Timestamped<AisMessage> getTimestampedMessage() {
186 		Long time = getTime();
187 		if (time == null)
188 			throw new RuntimeException("nmea did not have timestamp");
189 		else
190 			return Timestamped.create(getMessage(), getTime());
191 	}
192 
193 	/**
194 	 * Returns the checksum (last field in the NMEA line).
195 	 * 
196 	 * @return
197 	 */
198 	public String getChecksum() {
199 		return nmea.getChecksum();
200 	}
201 
202 	public NmeaMessage getNmea() {
203 		return nmea;
204 	}
205 }