package org.signalml.app.worker.monitor;
import static org.signalml.app.util.i18n.SvarogI18n._;
import static org.signalml.app.util.i18n.SvarogI18n._R;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import org.apache.log4j.Logger;
import org.signalml.app.SvarogApplication;
import org.signalml.app.worker.monitor.exceptions.OpenbciCommunicationException;
import org.signalml.app.worker.monitor.exceptions.OpenbciConnectionException;
import org.signalml.app.worker.monitor.messages.Message;
import org.signalml.app.worker.monitor.messages.MessageType;
import org.signalml.app.worker.monitor.messages.Netstring;
import org.signalml.app.worker.monitor.messages.parsing.MessageParser;
import org.signalml.util.FormatUtils;
/**
* This helper is used to send and receive messages from OpenBCI.
*
* @author Piotr Szachewicz
*/
public class Helper {
protected static Logger logger = Logger.getLogger(Helper.class);
private static Socket socket;
private static boolean cancelled;
/**
* The socket timeout used by this helper by default.
*/
public static final int DEFAULT_RECEIVE_TIMEOUT = 10000;
/**
* The constant holding a value for an infinite timeout.
*/
public static final int INFINITE_TIMEOUT = 0;
public static String getOpenBCIIpAddress() {
return SvarogApplication.getApplicationConfiguration().getOpenbciIPAddress();
}
public static int getOpenbciPort() {
return SvarogApplication.getApplicationConfiguration().getOpenbciPort();
}
public static Message sendRequestAndParseResponse(Message request, String destinationIP, int destinationPort, MessageType awaitedMessageType) throws OpenbciCommunicationException {
String responseString = sendRequest(request, destinationIP, destinationPort, DEFAULT_RECEIVE_TIMEOUT);
MessageParser.checkIfResponseIsOK(responseString, awaitedMessageType);
return MessageParser.parseMessageFromJSON(responseString, awaitedMessageType);
}
public static synchronized String sendRequest(Message request, String destinationIP,
int destinationPort, int timeout) throws OpenbciCommunicationException {
try {
return Helper.sendRequestWithoutHandlingExceptions(request, destinationIP, destinationPort, timeout);
} catch (OpenbciCommunicationException ex) {
if (cancelled) {
//cancelling receving results in throwing this exception
//so in this case we should ignore this exception.
return null;
}
else {
logger.error("", ex);
throw ex;
}
}
}
private static synchronized String sendRequestWithoutHandlingExceptions(Message request, String destinationIP,
int destinationPort, int timeout) throws OpenbciCommunicationException {
createSocket(destinationIP, destinationPort, timeout);
try {
sendMessage(request);
} catch (IOException e) {
logger.error("", e);
throw new OpenbciCommunicationException(_("I/O error occurred while writing to socket."));
}
String response;
try {
response = receiveResponse();
} catch (SocketTimeoutException e) {
logger.error("", e);
throw new OpenbciCommunicationException(_("Socket timeout exceeded while waiting for response"));
} catch (IOException e) {
logger.error("", e);
throw new OpenbciCommunicationException(_("I/O error occurred while reading from socket."));
}
try {
socket.close();
} catch (IOException e) {
logger.error("", e);
throw new OpenbciCommunicationException(_("I/O error occurred while closing the socket."));
}
return response;
}
private static void createSocket(String destinationIP, int destinationPort, int timeout) throws OpenbciCommunicationException {
cancelled = false;
try {
socket = new Socket(destinationIP, destinationPort);
socket.setSoTimeout(timeout);
} catch (UnknownHostException e) {
logger.error("", e);
String message = _R("Could not connect to {0}:{1}", destinationIP, FormatUtils.formatNoGrouping(destinationPort));
throw new OpenbciConnectionException(message, destinationIP, destinationPort);
} catch (ConnectException e) {
logger.error("", e);
String message = _R("Could not connect to {0}:{1} ({2})", destinationIP, FormatUtils.formatNoGrouping(destinationPort), e.getMessage());
throw new OpenbciConnectionException(message, destinationIP, destinationPort);
} catch (IOException e) {
logger.error("", e);
throw new OpenbciCommunicationException(_("I/O exception while creating a socket."));
}
}
private static void sendMessage(Message request) throws IOException {
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
Netstring netstring = new Netstring(request);
logger.debug("Sending message from "
+ socket.getLocalAddress() + ":" + socket.getLocalPort()
+ " to " + socket.getInetAddress() + ":" + socket.getPort()
+ ": " + netstring);
writer.println(netstring);
}
private static String receiveResponse() throws SocketTimeoutException, IOException, OpenbciCommunicationException {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String line;
do {
line = in.readLine();
if (line != null)
stringBuilder.append(line);
} while (line != null);
String response = stringBuilder.toString();
if (response == null || response.isEmpty())
throw new OpenbciCommunicationException(_("Received an empty response from openBCI!"));
Netstring responseNetstring = new Netstring();
responseNetstring.parseNetstring(response);
logger.debug("Got response: " + responseNetstring);
return responseNetstring.getData();
}
/**
* Cancels receiving all messages that this Helper is waiting for.
*/
public static void cancelReceiving() {
cancelled = true;
try {
socket.close();
} catch (IOException e) {
logger.error("", e);
}
}
}