/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package jaid.com;
import jaid.ais.data.ActiveTargetsMap;
import jaid.ais.message.AIVDM;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* This class represents the client that connects to a server and
* retrieves AIS messages.
*
* @author Benjamin Jakobus
* @since 1.0
* @version 1.0
*/
public class Client {
/* One minute in milliseconds */
private final static int ONE_MINUTE = 360000;
/* The port on which to connect to */
private int port;
/* The IP address of the server */
private String serverIP;
/**
* A map of currently active targets
* @see ActiveTargetsMap
*/
private ActiveTargetsMap activeTargetsMap;
/* The receiver's rxID */
private String rxID;
/* System timestamp used to determine when to run the garbage collector */
private long timeStamp;
/* Thirty seconds in milliseconds */
private static long THIRTY_SECONDS = 30000;
/* Determines whether or not this client is enabled */
private boolean isEnabled;
/* Thread maintaining the connection to the server */
private Thread connectionThread;
private Socket socket;
private PrintWriter outDataStrm;
private BufferedReader inDataStrm;
private AIVDM aivdmData;
private AIVDM aivdmMultiPart = null;
/* A list of pluggable modules that the client can use to decode
* custom messages.
*/
private List<ClientModule> clientModules;
/**
* Constructor.
*
* @param port The port on which to connect.
* @param serverIP The IP address of the server to which to connect.
* @param targetsMap The map into which to store the received targets.
* @param rxID The receiver's rxID.
* @since 1.0
*/
public Client(int port, String serverIP, ActiveTargetsMap targetsMap,
String rxID) {
this.port = port;
this.serverIP = serverIP;
this.activeTargetsMap = targetsMap;
this.rxID = rxID;
this.isEnabled = true;
timeStamp = System.currentTimeMillis();
clientModules = Collections.synchronizedList(new ArrayList<ClientModule>());
}
/**
* Starts the client (i.e. causes the client to start receiving messages).
*
* @since 1.0
*/
public void start() {
connectionThread = new Thread(new Runnable() {
public void run() {
while (isEnabled) {
connect();
System.out.println("Try reconnecting...");
try {
Thread.sleep(20000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
});
connectionThread.start();
}
/**
* Initializes connection with the server. Once connected, all incoming messages
* will be processed and stored.
*
* @since 1.0
*/
public void connect() {
try {
socket = new Socket(serverIP, port);
socket.setSoTimeout(ONE_MINUTE);
outDataStrm = new PrintWriter(socket.getOutputStream(), true);
inDataStrm = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String sentence;
while ((sentence = inDataStrm.readLine()) != null && isEnabled) {
outDataStrm.write("OK\n");
outDataStrm.flush();
if (sentence.indexOf("!AIVDM") == 0) {
//process sentence
try {
aivdmData = new AIVDM(sentence, rxID);
//Handle multi-slot messages - well 2 slot anyway...
switch (aivdmData.getNumMsgParts()) {
case 1:
//1 part message - types 1,2,3,4,18
aivdmData.parseSentence(activeTargetsMap);
break;
case 2:
//2 part message - types 5,19,21
if (aivdmData.getMsgPartNum() == 1) {
//store first part until we have second part
aivdmMultiPart = aivdmData;
} else {
//sentenceNum == 2
try { //part of the message may be corrupted/lost
aivdmMultiPart.append(aivdmData);
aivdmData = aivdmMultiPart;
aivdmData.parseSentence(activeTargetsMap);
// collectStats(_aivdmData);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
} catch (Exception e) {
System.out.println("Problem with AIVDM processing (" + rxID + " )... continuing");
}
} else {
if (rxID.contains("GEN")) {
System.out.println("size: " + clientModules.size());
}
for (ClientModule module : clientModules) {
module.interpret(sentence);
System.out.println("rec: " + sentence);
}
}
// Run the garbage collector every 60 seconds
if (System.currentTimeMillis() - timeStamp > THIRTY_SECONDS) {
System.gc();
timeStamp = System.currentTimeMillis();
}
}
System.out.println("Connection Terminated");
outDataStrm.close();
inDataStrm.close();
socket.close();
} catch (Exception e) {
System.out.println("Problems with " + rxID + " server");
e.printStackTrace();
}
}
/**
* Returns the receiver's rxID.
*
* @return rxID The receiver's rxID.
* @since 1.0
*/
public String getRxID() {
return rxID;
}
/**
* Enables / disables the client.
*
* @param enabled <code>True</code> if the client is to be enabled;
* <code>false</code> if not.
* @since 1.0
*/
public void setEnabled(boolean enabled) {
isEnabled = enabled;
}
/**
* Disconnects the client from its data source.
*
* @since 1.0
*/
public void disconnect() {
setEnabled(false);
}
/**
* Adds a custom module to the client.
*
* @param module
* @since 1.0
*/
public void addModule(ClientModule module) {
clientModules.add(module);
}
}