Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2010-2021 60East Technologies Inc., All Rights Reserved.
//
// This computer software is owned by 60East Technologies Inc. and is
// protected by U.S. copyright laws and other laws and by international
// treaties. This computer software is furnished by 60East Technologies
// Inc. pursuant to a written license agreement and may be used, copied,
// transmitted, and stored only in accordance with the terms of such
// license agreement and with the inclusion of the above copyright notice.
// This computer software or any other copies thereof may not be provided
// or otherwise made available to any other person.
//
// U.S. Government Restricted Rights. This computer software: (a) was
// developed at private expense and is in all respects the proprietary
// information of 60East Technologies Inc.; (b) was not developed with
// government funds; (c) is a trade secret of 60East Technologies Inc.
// for all purposes of the Freedom of Information Act; and (d) is a
// commercial item and thus, pursuant to Section 12.212 of the Federal
// Acquisition Regulations (FAR) and DFAR Supplement Section 227.7202,
// Government's use, duplication or disclosure of the computer software
// is subject to the restrictions set forth by 60East Technologies Inc..
//
////////////////////////////////////////////////////////////////////////////
package com.crankuptheamps.client;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.ByteBuffer;
import com.crankuptheamps.client.exception.StreamException;
/**
* Implements the ProtocolParser interface. Parses a byte stream
* using XML protocol.
*/
public class XMLProtocolParser implements ProtocolParser
{
private static final Charset LATIN1 = StandardCharsets.ISO_8859_1;
private static byte[] HEADER = null;
private static byte[] BODY = null;
private static byte[] BODY_TERMINAL = null;
private static byte[] BODY_EMPTY = null;
static
{
HEADER = "".getBytes(LATIN1);
BODY = "".getBytes(LATIN1);
BODY_TERMINAL = "".getBytes(LATIN1);
BODY_EMPTY = "".getBytes(LATIN1);
}
private XMLMessage message = null;
private ByteBuffer buffer = null;
private int remainingBytes = 0;
private enum StreamState
{
start, in_sow, end
}
private StreamState state;
public XMLProtocolParser(XMLProtocol messageType)
{
this.message = messageType.allocateMessage();
}
public void process(
ByteBuffer buffer,
int remainingBytes,
MessageHandler listener) throws StreamException
{
this.buffer = buffer;
this.remainingBytes = remainingBytes;
this.state = StreamState.start;
message.reset();
message.setBuffer(buffer.array());
while(read(message))
{
listener.invoke(message);
}
}
private static enum HeaderField
{
AckTyp,BkMrk,BtchSz,ClntName,Cmd,CmdId,DlvMd,
Drblty,Expn,Fltr,GrcPrd,GrpSqNum,Hrtbt,LeasePeriod,Matches,
MsgLn,Opts,PW,QId,QryIntvl,Reason,RecordsUpdated,RecordsInserted,
RecordsDeleted,RecordsReturned,Seq,SubIds,SowKey,SowKeys,Status,SubId,
Timestamp,TmIntvl,Tpc,TopicMatches,TopN,UsrId,Version,CrlId,
UNKNOWN
}
final private HeaderField extractHeaderField()
{
if(remainingBytes < 5 || getByte() != '<')
{
// Not enough room for the shortest tag ''
return HeaderField.UNKNOWN;
}
// Find the end of the tag, so that we can optimize the field lookup
int length = 0;
int start = buffer.position();
while(remainingBytes > 0 && getByte() != '>')
{
++length;
}
switch(peekByte(start))
{
case 'A':
if(length == 6)
{
return HeaderField.AckTyp;
}
else return HeaderField.UNKNOWN;
case 'B':
if(length == 5) return HeaderField.BkMrk;
if(length != 6) return HeaderField.UNKNOWN;
if(peekByte(start+4) == 'S')
{
return HeaderField.BtchSz;
}
return HeaderField.UNKNOWN;
case 'C':
switch(length)
{
case 3: // Cmd
return HeaderField.Cmd;
case 5: // CmdId
switch(peekByte(start+1))
{
case 'm':return HeaderField.CmdId;
case 'r':return HeaderField.CrlId;
}
return HeaderField.UNKNOWN;
case 8: // ClntName
return HeaderField.ClntName;
default:
return HeaderField.UNKNOWN;
}
case 'D':
switch(length)
{
case 5: // DlvMd
return HeaderField.DlvMd;
case 6: // Drblty
return HeaderField.Drblty;
default:
return HeaderField.UNKNOWN;
}
case 'E':
if(length == 4)
{
advance(length);
return HeaderField.Expn;
}
else return HeaderField.UNKNOWN;
case 'F':
if(length == 4)
{
return HeaderField.Fltr;
}
else return HeaderField.UNKNOWN;
case 'G':
switch(length)
{
case 6: // GrcPrd
return HeaderField.GrcPrd;
case 8: // GrpSqNum
return HeaderField.GrpSqNum;
default:
return HeaderField.UNKNOWN;
}
case 'H':
if(length == 4)
{
return HeaderField.Hrtbt;
}
else return HeaderField.UNKNOWN;
case 'L':
switch(length)
{
case 11:
return HeaderField.LeasePeriod;
default:
return HeaderField.UNKNOWN;
}
case 'M':
switch(length)
{
case 5: // MsgLn
return HeaderField.MsgLn;
case 7: // Matches
return HeaderField.Matches;
default:
return HeaderField.UNKNOWN;
}
case 'O':
switch(length)
{
case 4: // Opts
return HeaderField.Opts;
default:
return HeaderField.UNKNOWN;
}
case 'P':
switch(length)
{
case 2: // PW
return HeaderField.PW;
default:
return HeaderField.UNKNOWN;
}
case 'Q':
switch(length)
{
case 3: // QId
return HeaderField.QId;
default:
return HeaderField.UNKNOWN;
}
case 'R':
switch(length)
{
case 6: // Reason
return HeaderField.Reason;
case 15:
switch(peekByte(start+7))
{
case 'R': // RecordsReturned
return HeaderField.RecordsReturned;
case 'I': // RecordsInserted
return HeaderField.RecordsInserted;
default:
return HeaderField.UNKNOWN;
}
case 14:
switch(peekByte(start+7))
{
case 'D': // RecordsDeleted
return HeaderField.RecordsDeleted;
case 'U': // RecordsUpdated
return HeaderField.RecordsUpdated;
default:
return HeaderField.UNKNOWN;
}
default:
return HeaderField.UNKNOWN;
}
case 'S':
switch(length)
{
case 3: // Seq
return HeaderField.Seq;
case 5: // SubId
return HeaderField.SubId;
case 6: // SubIds,SndOOF,SowKey,Status
switch(peekByte(start+1))
{
case 'u': // SubIds
return HeaderField.SubIds;
case 'o': // SowKey
return HeaderField.SowKey;
case 't': // Status
return HeaderField.Status;
default:
return HeaderField.UNKNOWN;
}
case 7: // SowKeys
return HeaderField.SowKeys;
default:
return HeaderField.UNKNOWN;
}
case 'T':
switch(length)
{
case 3: // Tpc
return HeaderField.Tpc;
case 4: // TopN
return HeaderField.TopN;
case 5: // TxmTm
return HeaderField.Timestamp;
case 7: // TmIntvl
return HeaderField.TmIntvl;
default:
return HeaderField.UNKNOWN;
}
case 'U':
if(length != 5) return HeaderField.UNKNOWN;
switch(peekByte(start+2))
{
case 'r': // UsrId
return HeaderField.UsrId;
default:
return HeaderField.UNKNOWN;
}
case 'V':
if(length != 7) return HeaderField.UNKNOWN;
return HeaderField.Version;
default:
return HeaderField.UNKNOWN;
}
}
final private char getUnescapedChar(int startPos)
{
switch(peekByte(startPos+1))
{
case 'a':
switch(peekByte(startPos+2))
{
case 'm': //amp;
return '&';
case 'p': //apos;
return '\'';
}
case 'l':
return '<';
case 'g':
return '>';
case 'q':
return '\"';
default:
return 0x00;
}
}
final private int processEscapeField()
{
int b = buffer.position();
int valueLength = 0;
while(peekByte(buffer.position()) != '<')
{
if(peekByte(buffer.position()) == '&')
{
char unescapedChar = getUnescapedChar(buffer.position());
this.buffer.put(b++, (byte)unescapedChar);
advancePast((byte)';');
}
else
this.buffer.put(b++, getByte());
++valueLength;
}
return valueLength;
}
final private void extractFieldValues(XMLMessage message)
{
HeaderField field = extractHeaderField();
while(field != HeaderField.UNKNOWN)
{
boolean needsEscape = (field == HeaderField.Tpc || field == HeaderField.UsrId ||
field == HeaderField.PW || field == HeaderField.ClntName ||
field == HeaderField.CrlId || field == HeaderField.SubId ||
field == HeaderField.SubIds);
// Have a header field, let's extract the value
int valueStart = buffer.position();
int valueLength = 0;
if(needsEscape)
valueLength = processEscapeField();
else
{
while(remainingBytes > 0 && getByte() != '<')
++valueLength;
}
switch(field)
{
case AckTyp:
message._AckType.set(this.buffer.array(),valueStart,valueLength);
break;
case BtchSz:
message._BatchSize.set(this.buffer.array(),valueStart,valueLength);
break;
case BkMrk:
message._Bookmark.set(this.buffer.array(),valueStart,valueLength);
break;
case ClntName:
message._ClientName.set(this.buffer.array(),valueStart,valueLength);
break;
case Cmd:
message._Command.set(this.buffer.array(),valueStart,valueLength);
break;
case CmdId:
message._CommandId.set(this.buffer.array(),valueStart,valueLength);
break;
case CrlId:
message._CorrelationId.set(this.buffer.array(),valueStart,valueLength);
break;
case Expn:
message._Expiration.set(this.buffer.array(),valueStart,valueLength);
break;
case Fltr:
message._Filter.set(this.buffer.array(),valueStart,valueLength);
break;
case GrpSqNum:
message._GroupSeqNo.set(this.buffer.array(),valueStart,valueLength);
break;
// case Hrtbt: message._Heartbeat.set(this.buffer.array(),valueStart,valueLength); break;
case LeasePeriod:
message._LeasePeriod.set(this.buffer.array(),valueStart,valueLength);
break;
case Matches:
message._Matches.set(this.buffer.array(),valueStart,valueLength);
break;
case MsgLn:
message._Length.set(this.buffer.array(),valueStart,valueLength);
break;
case Opts:
message._Options.set(this.buffer.array(),valueStart,valueLength);
break;
case PW:
message._Password.set(this.buffer.array(),valueStart,valueLength);
break;
case QId:
message._QueryId.set(this.buffer.array(),valueStart,valueLength);
break;
case Reason:
message._Reason.set(this.buffer.array(),valueStart,valueLength);
break;
case RecordsInserted:
message._RecordsInserted.set(this.buffer.array(),valueStart,valueLength);
break;
case RecordsUpdated :
message._RecordsUpdated.set(this.buffer.array(),valueStart,valueLength);
break;
case RecordsReturned:
message._RecordsReturned.set(this.buffer.array(),valueStart,valueLength);
break;
case RecordsDeleted :
message._RecordsDeleted.set(this.buffer.array(),valueStart,valueLength);
break;
case Seq:
message._Sequence.set(this.buffer.array(),valueStart,valueLength);
break;
case SubIds:
message._SubIds.set(this.buffer.array(),valueStart,valueLength);
break;
case SowKey:
message._SowKey.set(this.buffer.array(),valueStart,valueLength);
break;
case SowKeys:
message._SowKeys.set(this.buffer.array(),valueStart,valueLength);
break;
case Status:
message._Status.set(this.buffer.array(),valueStart,valueLength);
break;
case SubId:
message._SubId.set(this.buffer.array(),valueStart,valueLength);
break;
case Timestamp:
message._Timestamp.set(this.buffer.array(),valueStart,valueLength);
break;
// case TmIntvl: message._TimeoutInterval.set(this.buffer.array(),valueStart,valueLength); break;
case Tpc:
message._Topic.set(this.buffer.array(),valueStart,valueLength);
break;
case TopicMatches:
message._TopicMatches.set(this.buffer.array(),valueStart,valueLength);
break;
case TopN:
message._TopN.set(this.buffer.array(),valueStart,valueLength);
break;
case UsrId:
message._UserId.set(this.buffer.array(),valueStart,valueLength);
break;
case Version:
message._Version.set(this.buffer.array(),valueStart,valueLength);
break;
default:
break;
}
// Strip to end of this tag
while(remainingBytes > 0 && getByte() != '>')
{
; // Just advancing past the tag
}
field = extractHeaderField();
}
}
private static byte[] SOW_KEYID = null;
private static byte[] SOW_LEN = null;
private static byte[] SOW_TS = null;
private static byte[] SOW_X = null;
private static byte DBL_QUOTE = 0;
private static byte GREATER_THAN = 0;
static
{
SOW_KEYID = " key=\"".getBytes(LATIN1);
SOW_LEN = " len=\"".getBytes(LATIN1);
SOW_TS = " ts=\"".getBytes(LATIN1);
SOW_X = " x=\"".getBytes(LATIN1);
DBL_QUOTE = "\"".getBytes(LATIN1)[0];
GREATER_THAN = ">".getBytes(LATIN1)[0];
}
final private boolean extractSOWHeaderFields(XMLMessage message)
{
int position = advancePast(SOW_KEYID);
if(position < 0)
{
// No SowKey
return false;
}
// Read Key
if(advancePast(DBL_QUOTE) < 0)
{
// broken record
return false;
}
message._SowKey.set(buffer.array(),position,buffer.position()-position-1);
// We've had the length in the past, let's assume we always have it
position = advancePast(SOW_LEN);
if(position < 0)
{
// No len, but had one in the past?
return false;
}
// Read Key
if(advancePast(DBL_QUOTE) < 0)
{
// broken record
return false;
}
message._Length.set(buffer.array(),position,buffer.position()-position-1);
position = buffer.position();
if(peekByte(position+1)=='t' && peekByte(position+2)=='s')
{
position=advancePast(SOW_TS);
advancePast(DBL_QUOTE);
message._Timestamp.set(buffer.array(),position,buffer.position()-position-1);
}
position = buffer.position();
if(peekByte(position+1)=='x' && peekByte(position+2)=='=')
{
position=advancePast(SOW_X);
advancePast(DBL_QUOTE);
message._CorrelationId.set(buffer.array(),position,buffer.position()-position-1);
}
// Advance to the start of the sow record body
if(advancePast(GREATER_THAN) < 0)
{
return false;
}
// Body starts at buffer.position and the message length exists
position = buffer.position();
int len = message.getLength();
message.setRawBufferLength(position + len - message.getRawBufferOffset());
message._Data.set(buffer.array(),position,len);
return true;
}
// Returns position after sequence or -1 if not found
private int advancePast(byte[] t)
{
for(int position = buffer.position(); position < buffer.position()+remainingBytes-t.length; ++position)
{
boolean found = true;
for(int i = 0; i < t.length; ++i)
{
if(peekByte(position+i) != t[i])
{
found = false;
break;
}
}
if(found)
{
position += t.length;
remainingBytes -= position-buffer.position();
buffer.position(position);
return position;
}
}
return -1;
}
private int advancePast(byte t)
{
int c = remainingBytes;
while(c-- > 0)
{
if(getByte() == t)
{
remainingBytes = c;
return buffer.position();
}
}
return -1;
}
private final void advance(int bytes)
{
remainingBytes -= bytes;
buffer.position(buffer.position()+bytes);
}
private int findBytes(byte[] t)
{
for(int position = buffer.position(); position < buffer.limit()-t.length; ++position)
{
boolean found = true;
for(int i = 0; i < t.length; ++i)
{
if(peekByte(position+i) != t[i])
{
found = false;
break;
}
}
if(found) return position;
}
return -1;
}
private final byte getByte()
{
--remainingBytes;
return buffer.get();
}
// Peek forward by offset bytes
private final byte peekByte(int offset)
{
return buffer.get(offset);
}
private boolean read(XMLMessage m) throws StreamException
{
if(remainingBytes <= 0)
{
// No more messages in this stream
return false;
}
int position;
if(state == StreamState.start)
{
// First time through, let's setup the header
m.setRawBufferOffset(buffer.position());
position = advancePast(HEADER);
if(position < 0)
{
throw new StreamException("stream corruption: couldn't locate XML SOAP header.");
}
extractFieldValues(m);
// The first message in a SOW message sets all parts of the header
if(m.getCommand() == Message.Command.SOW)
{
if(advancePast(BODY) < 0)
{
throw new StreamException("stream corruption: couldn't locate XML SOAP body.");
}
if(!extractSOWHeaderFields(m))
{
throw new StreamException("stream corruption: couldn't locate message segment within XML SOAP body.");
}
state = StreamState.in_sow;
}
else // Not a SOW message, so it's just a standard message
{
int bodyStart;
if(advancePast(BODY) < 0)
{
// not found, let's check for empty body
if(advancePast(BODY_EMPTY) >= 0)
{
bodyStart = buffer.position();
position = bodyStart;
}
else // let's assume a naked body
{
bodyStart = buffer.position();
position = bodyStart + remainingBytes;
}
}
else
{
bodyStart = buffer.position();
position = findBytes(BODY_TERMINAL);
if(position < 0)
{
throw new StreamException("stream corruption: couldn't locate XML SOAP body end.");
}
}
m.setRawBufferLength(position-m.getRawBufferOffset());
m._Data.set(this.buffer.array(),bodyStart,position-bodyStart);
state = StreamState.end;
advance(remainingBytes);
}
}
else if(state == StreamState.in_sow)
{
if(!extractSOWHeaderFields(m))
{
state = StreamState.end;
advance(remainingBytes);
return false;
}
}
else return false;
return true;
}
/* Comment since not used.
private void dumpBuffer(String prefix)
{
System.err.print(prefix);
for(int j = buffer.position(); j < buffer.limit(); ++j)
{
try
{
System.err.print(new String(buffer.array(),j,1,LATIN1));
}
catch(Exception e)
{
System.err.print("{error}");
}
}
System.err.println();
}
*/
}