package org.opennaas.extensions.protocols.tl1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.BlockingQueue;
import org.opennaas.extensions.protocols.tl1.message.TL1OutputMsg;
import org.opennaas.extensions.protocols.tl1.message.TL1OutputParser;
import org.opennaas.extensions.protocols.tl1.message.TL1ParserException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TL1StreamReader extends Thread {
/** Logger */
static private Logger logger = LoggerFactory.getLogger(TL1StreamReader.class);
/** The queue where parsed response message are sent **/
private BlockingQueue<TL1OutputMsg> syncResponseQueue;
/** Int value for Carriage Return */
public static final int CR = 13;
/** Int value for Line Feed */
public static final int LF = 10;
/** Int value for valid character start */
public static final int VALIDSTART = 31;
/** Int value for valid character stop */
public static final int VALIDSTOP = 127;
/** Input Reader from TCP Port */
private BufferedReader inRead;
/** String Buffer to input Data */
private StringBuilder buffer = new StringBuilder();
/** Die variable will kill the reader thread when set to true */
public boolean die = false;
/** Characters to look for that flag the end of a message */
private char[] msgdelimiters;
/** The number of characters to look back in the stringbuffer to try and match the prompt */
private int promptOffset = 50;
/**
* The network element's promt string to use to detect the end of a message. This is used in conjunction with the msgdelimiters to find the end of
* a message
*/
private String[] prompts = null;
/**
* The tL1 session that this stream reader reports to
*/
private TL1ProtocolSession tl1Session = null;
/**
* Constructor that Creates a TL1 Stream reader from an Input Stream
*
* @param in
* @param msgdeli
* the message delimiters
* @param syncResponseQueue
* the response queue where response messages and acks will be sent
* @param eventAdmin
* used to send notifications about autonomous messages
* @param topic
* the topic of the notifications
*/
public TL1StreamReader(InputStream in, char[] msgdeli, BlockingQueue<TL1OutputMsg> syncResponseQueue,
TL1ProtocolSession tl1Session) {
inRead = new BufferedReader(new InputStreamReader(in));
msgdelimiters = msgdeli;
this.syncResponseQueue = syncResponseQueue;
this.tl1Session = tl1Session;
}
/**
* Constructor that Creates a TL1 Stream reader from an Input Stream
*
* @param in
* @param msgdeli
* the message delimiters
* @param prompts
* @param promptOffset
* @param syncResponseQueue
* the response queue where response messages and acks will be sent
* @param eventAdmin
* used to send notifications about autonomous messages
* @param topic
* the topic of the notifications
*/
public TL1StreamReader(InputStream in, char[] msgdeli, String[] prompts, int promptOffset,
BlockingQueue<TL1OutputMsg> syncResponseQueue, TL1ProtocolSession tl1Session) {
inRead = new BufferedReader(new InputStreamReader(in));
msgdelimiters = msgdeli;
this.prompts = prompts;
this.promptOffset = promptOffset;
this.syncResponseQueue = syncResponseQueue;
this.tl1Session = tl1Session;
}
/**
* Gets the different valid characters when the thread starts and puts them in a buffer
*
* @see java.lang.Runnable#run()
*/
public void run() {
try {
int c;
while (((c = inRead.read()) != -1) && (!die)) {
if ((c > VALIDSTART && c < VALIDSTOP) || c == LF || c == CR) {
buffer.append((char) c);
for (int i = 0; i < msgdelimiters.length; i++) {
if ((char) c == msgdelimiters[i]) {
if (buffer.toString().indexOf("REPT EVT SESSION") == -1) {
// look back for prompt if it has been set
if (prompts != null) {
int startIndex = 0;
// Make sure the start index is not a negative integer
if (buffer.length() < promptOffset) {
startIndex = 0;
} else {
startIndex = buffer.length() - promptOffset;
}
// loop over the list of possible prompts to look for a match
for (int j = 0; j < prompts.length; j++) {
if (buffer.toString().substring(startIndex).indexOf(
prompts[j]) != -1) {
logger.debug("Message received, I'm going to process it");
processMessage((String) buffer.toString());
buffer = new StringBuilder();
break;
}
}
} else {
logger.debug("Message received, I'm going to process it");
processMessage((String) buffer.toString());
buffer = new StringBuilder();
}
}
break;
}
}
}
}
if (streamIsClosed(c)) {
logger.debug("Connection Lost!");
tl1Session.restartSession();
}
} catch (IOException e) {
logger.debug("Connection Lost!" + e.getMessage());
tl1Session.restartSession();
}
}
private boolean streamIsClosed(int c) {
if (c == -1) {
return true;
} else {
return false;
}
}
/**
* Parse the TL1 message and either put it in the response queue (ACKs and Response messages) or send a notification (Autonomous messages)
*
* @param message
*/
private void processMessage(String message) {
TL1OutputMsg tl1Message = null;
// Parse the plain text message
try {
tl1Message = TL1OutputParser.parse(message);
} catch (TL1ParserException e) {
logger.error("\n***********\n" +
"Error parsing message:\n" + e.getMessage() +
"\n***********\n");
return;
}
// Process the message based on its type
if (tl1Message != null) {
switch (tl1Message.getType()) {
case TL1OutputMsg.PROMPT_TYPE:
logger.debug("Received PROMPT, ignore it");
break;
case TL1OutputMsg.AUTO_TYPE:
logger.debug("Received TL1 Autonomous message, sending notification");
tl1Session.notify(tl1Message);
break;
case TL1OutputMsg.ACK_TYPE:
logger.debug("Received TL1 ACK message, adding it to the queue");
syncResponseQueue.add(tl1Message);
break;
default:
logger.debug("Received TL1 response message, adding it to the queue");
syncResponseQueue.add(tl1Message);
break;
}
}
}
}