PipelinedMsgParserpublic final class PipelinedMsgParser extends Object implements RunnableThis implements a pipelined message parser suitable for use
with a stream - oriented input such as TCP. The client uses
this class by instatiating with an input stream from which
input is read and fed to a message parser.
It keeps reading from the input stream and process messages in a
never ending interpreter loop. The message listener interface gets called
for processing messages or for processing errors. The payload specified
by the content-length header is read directly from the input stream.
This can be accessed from the Message using the getContent and
getContentBytes methods provided by the Message class. |
Fields Summary |
---|
protected SIPMessageListener | sipMessageListenerThe message listener that is registered with this parser.
(The message listener has methods that can process correct
and erroneous messages.) | private Thread | mythreadHandle to the preprocssor thread. | private InputStream | rawInputStreamRaw data input to be processed. |
Constructors Summary |
---|
protected PipelinedMsgParser()Default constructor.
super();
| public PipelinedMsgParser(SIPMessageListener sipMessageListener, InputStream in, boolean debug)Constructor when we are given a message listener and an input stream
(could be a TCP connection or a file)
this();
this.sipMessageListener = sipMessageListener;
rawInputStream = in;
mythread = new Thread(this);
| public PipelinedMsgParser(SIPMessageListener mhandler, InputStream in)This is the constructor for the pipelined parser.
this(mhandler, in, false);
| public PipelinedMsgParser(InputStream in)This is the constructor for the pipelined parser.
this(null, in, false);
|
Methods Summary |
---|
protected java.lang.Object | clone()Create a new pipelined parser from an existing one.
PipelinedMsgParser p = new PipelinedMsgParser();
p.rawInputStream = this.rawInputStream;
p.sipMessageListener = this.sipMessageListener;
return p;
| public void | processInput()Start reading and processing input.
mythread.start();
| private java.lang.String | readLine(java.io.InputStream inputStream)Reads a line of input (I cannot use buffered reader because we
may need to switch encodings mid-stream!
StringBuffer retval = new StringBuffer("");
while (true) {
char ch;
int i = inputStream.read();
if (i == -1) {
throw new IOException("End of stream");
} else {
ch = (char) i;
}
if (ch != '\r") {
retval.append(ch);
}
if (ch == '\n") {
break;
}
}
return retval.toString();
| private java.lang.String | readToBreak(java.io.InputStream inputStream)Reads to the next break (CRLFCRLF sequence).
StringBuffer retval = new StringBuffer("");
boolean flag = false;
while (true) {
char ch;
int i = inputStream.read();
if (i == -1)
break;
else
ch = (char) i;
if (ch != '\r")
retval.append(ch);
if (ch == '\n") {
if (flag)
break;
else
flag = true;
}
}
return retval.toString();
| public void | run()This is input reading thread for the pipelined parser.
You feed it input through the input stream (see the constructor)
and it calls back an event listener interface for message
processing or error.
It cleans up the input - dealing with things like line continuation
InputStream inputStream = this.rawInputStream;
// I cannot use buffered reader here because we may need to switch
// encodings to read the message body.
try {
while (true) {
StringBuffer inputBuffer = new StringBuffer();
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
"Starting parse!");
}
String line1;
String line2 = null;
// ignore blank lines.
while (true) {
line1 = readLine(inputStream);
if (line1.equals("\n")) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_JSR180,
"Discarding " + line1);
}
continue;
} else {
break;
}
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
"line1 = " + line1);
}
inputBuffer.append(line1);
while (true) {
line2 = readLine(inputStream);
inputBuffer.append(line2);
if (line2.trim().equals("")) break;
}
inputBuffer.append(line2);
StringMsgParser smp =
new StringMsgParser(sipMessageListener);
smp.readBody = false;
Message sipMessage = null;
try {
sipMessage =
smp.parseSIPMessage(inputBuffer.toString());
if (sipMessage == null) continue;
} catch (ParseException ex) {
// Just ignore the parse exception.
continue;
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
"Completed parsing message");
}
ContentLengthHeader cl =
sipMessage.getContentLengthHeader();
int contentLength = 0;
if (cl != null) {
contentLength = cl.getContentLength();
} else {
contentLength = 0;
}
if (contentLength == 0) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_JSR180,
"content length " + contentLength);
}
sipMessage.removeContent();
} else { // deal with the message body.
contentLength = cl.getContentLength();
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_JSR180,
"content length " + contentLength);
}
byte[] message_body = new byte[contentLength];
int nread = 0;
while (nread < contentLength) {
int readlength =
inputStream.read
(message_body, nread,
contentLength -
nread);
if (readlength > 0) {
nread += readlength;
if (Logging.REPORT_LEVEL <=
Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_JSR180,
"read " + nread);
}
} else {
break;
}
}
sipMessage.setMessageContent(message_body);
}
if (sipMessageListener != null) {
sipMessageListener.processMessage(sipMessage);
}
}
} catch (IOException ex) {
if (sipMessageListener != null) {
sipMessageListener.handleIOException();
}
} finally {
}
| public void | setMessageListener(SIPMessageListener mlistener)Add a class that implements a MessageListener interface whose
methods get called * on successful parse and error conditons.
sipMessageListener = mlistener;
|
|