com.crankuptheamps.client.CompositeMessageParser Maven / Gradle / Ivy
////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2010-2022 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.CharsetDecoder;
import com.crankuptheamps.client.fields.Field;
/**
* Used to retrieve individual message parts from AMPS composite messages,
* which are messages where the data contains a number of parts and each part
* is a complete message of a specific message type.
* For example, a composite message type of "composite-json-binary" may be
* declared on the server that combines a set of JSON headers with
* an opaque binary payload. CompositeMessageParser makes it easy to retrieve
* the parts of a composite message from the composite message payload.
*
*/
public class CompositeMessageParser
{
/**
* Creates a new CompositeMessageParser, with 0 valid parts.
*/
public CompositeMessageParser()
{
_metadata = new int[MAX_PARTS * 2];
_validCount = 0;
}
/**
* Creates a new CompositeMessageParser and parses the provided message body.
* @param body_ The composite body (returned from Message.getDataRaw()).
*/
public CompositeMessageParser(Field body_)
{
_metadata = new int[MAX_PARTS * 2];
parse(body_);
}
/**
* Creates a new CompositeMessageParser and parses a message's body.
* @param message_ The message containing a composite body.
*/
public CompositeMessageParser(Message message_)
{
_metadata = new int[MAX_PARTS * 2];
parse(message_.getDataRaw());
}
/**
* Parses a composite message.
* @param message_ The message with a composite body.
* @return The number of message parts found in message_
*/
public final int parse(Message message_)
{
return parse(message_.getDataRaw());
}
/**
* Parses a composite message's body.
* @param body_ The composite body (returned from Message.getDataRaw()).
* @return The number of message parts found in body_
*/
public final int parse(Field body_)
{
_validCount = 0;
// Skip through the body buffer, and write offsets to our internal _offset array.
int position = body_.position;
int end = position + body_.length;
byte[] buf = body_.buffer;
int metaIndex = 0;
while(position+4 <= end)
{
// extract part length
int partlength = (buf[position++]&0xFF) << 24;
partlength |= (buf[position++]&0xFF) << 16;
partlength |= (buf[position++]&0xFF) << 8;
partlength |= (buf[position++]&0xFF);
_metadata[metaIndex++] = position;
_metadata[metaIndex++] = partlength;
position += partlength;
}
_data = buf;
_validCount = metaIndex/2;
return _validCount;
}
/**
* Returns a part from a composite message body.
* @param index_ The part index to retrieve (0-based index)
* @return The data of this body part, decoded as UTF-8.
*/
public String getString(int index_)
{
return getString(index_,UTF8);
}
/**
* Returns a part from a composite message body.
* @param index_ The part index to retrieve (0-based index)
* @param charset The Charset to decode this body with.
* @return The data of this body part.
*/
public String getString(int index_,Charset charset)
{
if(index_ < _validCount)
{
return new String(_data,_metadata[index_*2],_metadata[(index_*2)+1],charset);
}
throw new RuntimeException("index out of bounds.");
}
/**
* Returns a part from a composite message body.
* @param index_ The part index to retrieve (0-based index)
* @param field_ The Field to update with the buffer, index, and length of this part.
* @return The field passed as field_.
*/
public Field getPart(int index_,Field field_)
{
if(index_ < _validCount)
{
field_.buffer = _data;
field_.position = _metadata[index_*2];
field_.length = _metadata[(index_*2)+1];
return field_;
}
throw new RuntimeException("index out of bounds.");
}
//Private Methods
private static int MAX_PARTS = 1024;
private static Charset UTF8 = Charset.forName("UTF-8");
private int[] _metadata = null;
private byte[] _data = null;
private int _validCount;
}