com.crankuptheamps.client.fields.BookmarkRangeField Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of amps-client Show documentation
Show all versions of amps-client Show documentation
AMPS Java client by 60East Technologies, Inc.
////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2010-2020 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.fields;
import java.lang.System;
import java.util.zip.CRC32;
/**
* Field data for a {@link com.crankuptheamps.client.Message} consisting of the bookmark.
* This is the AMPS Bookmark for the Message.
*/
public class BookmarkRangeField extends BookmarkField
{
private int _capacity = 0;
private BookmarkField _start = null;
private BookmarkField _end = null;
private int _open = -1;
/**
* Overrides the base classes' initial default size for the byte and
* char conversion buffers used by this instance. Defaults to 128
* which is sufficient for 2 bookmarks and associated chars.
*
* @return Returns a default size of 128.
*/
@Override
protected int getConversionBufInitialSize() { return 128; }
protected BookmarkRangeField(byte[] buffer, int position, int length)
{
super(buffer, position, length);
_capacity = length;
parse();
}
public BookmarkRangeField()
{
}
@Override
public void copyFrom(Field f)
{
if (f == null || f.length == 0) {
length = 0;
position = 0;
notValid();
return;
}
if (buffer == null || f.length > _capacity)
{
buffer = new byte[f.length];
_capacity = f.length;
}
// Start copy where range starts
int start = 0;
while (start < f.length && f.buffer[f.position+start] != (byte)'['
&& f.buffer[f.position+start] != (byte)'(')
{
++start;
}
if (start < f.length) {
length = f.length - start;
System.arraycopy(f.buffer, f.position + start, buffer, 0, length);
position = 0;
parse();
}
else {
length = 0;
notValid();
}
}
public boolean isValid()
{
return _open >= 0;
}
public BookmarkField getStart()
{
return _start;
}
public BookmarkField getEnd()
{
return _end;
}
public boolean isStartInclusive()
{
if (isValid()) {
return this.buffer[_open] == (byte)'[';
}
return false;
}
public boolean isEndInclusive()
{
if (isValid()) {
return this.buffer[position+length-1] == (byte)']';
}
return false;
}
public boolean isStartExclusive()
{
if (isValid()) {
return this.buffer[_open] == (byte)'(';
}
return false;
}
public boolean isEndExclusive()
{
if (isValid()) {
return this.buffer[position+length-1] == (byte)')';
}
return false;
}
public void replaceStart(Field start_)
{
replaceStart(start_, true);
}
public void replaceStart(Field start_, boolean makeExclusive)
{
if (!isValid()) return;
// Don't go backwards
BookmarkField startBm = (BookmarkField)start_;
if (startBm.getPublisherId() == _start.getPublisherId()
&& startBm.getSequenceNumber() <= _start.getSequenceNumber())
{
if (makeExclusive && startBm.getSequenceNumber()
== _start.getSequenceNumber())
{
buffer[position+_open] = (byte)'(';
}
return;
}
int newLen = start_.length + _end.length + 3;
// Check if new start fits in our buffer
if (_capacity >= newLen) {
if (makeExclusive) buffer[position+_open] = (byte)'(';
if (_open > 0) {
buffer[position] = buffer[position + _open];
_open = 0;
}
if (_end.position < start_.length + 2) {
// Move end toward the end to make room
for (int pos = newLen-1, src = length-1; src > _start.length; --pos, --src) {
while (buffer[position+src] == (byte)' ') {
--src;
}
buffer[position+pos] = buffer[position+src];
if (buffer[position+src] == (byte)':') {
_end.set(buffer, start_.length+2, _end.length);
break;
}
}
}
else if (_end.position > start_.length + 2) {
// Move end toward the start
for (int pos = start_.length+2, src = _end.position; src < length; ++pos, ++src) {
while (buffer[position+src] == (byte)' ') {
++src;
}
buffer[position+pos] = buffer[position+src];
if (buffer[position+src] == (byte)']' || buffer[position+src] == (byte)')')
{
_end.set(buffer, position+start_.length+2, _end.length);
buffer[position+start_.length+1] = (byte)':';
break;
}
}
}
length = newLen;
System.arraycopy(start_.buffer, start_.position, buffer, position+1, start_.length);
_start.set(buffer, position+1, start_.length);
}
else {
_capacity = Math.max(4*BookmarkField.MAX_BOOKMARK_LENGTH + 6,
start_.length + _end.length + 3);
byte[] tmpBuffer = new byte[_capacity];
if (makeExclusive) tmpBuffer[0] = (byte)'(';
else tmpBuffer[0] = buffer[_open];
_open = 0;
System.arraycopy(start_.buffer, start_.position, tmpBuffer, position+1, start_.length);
_start.set(tmpBuffer, 1, start_.length);
tmpBuffer[start_.length+1] = (byte)':';
System.arraycopy(_end.buffer, _end.position, tmpBuffer, start_.length+2, _end.length);
_end.set(tmpBuffer, start_.length+2, _end.length);
tmpBuffer[newLen-1] = buffer[length-1];
set(tmpBuffer, 0, newLen);
}
}
/**
* Provides a way to duplicate this object and retain its specific type (and hashcode() implementation).
*/
public BookmarkRangeField clone()
{
byte[] copy = null;
if (buffer != null) {
copy = new byte[length];
System.arraycopy(buffer, position, copy, 0, length);
}
return new BookmarkRangeField(copy, 0, length);
}
// Override base class's copy() method appropriately, so we don't inadvertently mix
// BookmarkRangeFields and Fields up -- they have different hashCode implementations.
@Override
public BookmarkRangeField copy()
{
return clone();
}
@Override
public int hashCode()
{
c.reset();
c.update(buffer, position, length);
return (int)c.getValue();
}
@Override
public boolean equals(Object object_)
{
// Are we comparing to something valid
if (object_ == null || !(object_ instanceof BookmarkRangeField)) {
return false;
}
BookmarkRangeField rhs = (BookmarkRangeField)object_;
// Is one an invalid range
if ((_start == null && rhs._start != null)
|| (_start != null && rhs._start == null)) {
return false;
}
// Compare logically equal
return isStartInclusive() == rhs.isStartInclusive()
&& isEndInclusive() == rhs.isEndInclusive()
&& _start.equals(rhs._start) && _end.equals(rhs._end);
}
private void notValid()
{
_start = null;
_end = null;
_open = -1;
}
private void parse()
{
notValid();
boolean foundClose = false;
boolean foundSeparator = false;
int pos = this.position;
int end = this.position + length;
while (pos < end) {
switch (buffer[pos]) {
// Range start
case (byte)'(':
case (byte)'[':
{
// Can't be past the end or alredy started
if (foundClose || _open > -1) {
notValid();
return;
}
_open = pos;
}
break;
// Valid characters for start or end portions of the range
case (byte)'0':
case (byte)'1':
case (byte)'2':
case (byte)'3':
case (byte)'4':
case (byte)'5':
case (byte)'6':
case (byte)'7':
case (byte)'8':
case (byte)'9':
case (byte)'|':
case (byte)',':
case (byte)'T':
case (byte)'Z':
case (byte)'.':
{
// Have to be between start and end
if (foundClose || _open < 0) {
notValid();
return;
}
else if (foundSeparator) {
if (_end == null) {
// Create the _end field, length will change
_end = new BookmarkField();
_end.set(this.buffer, pos, end - pos);
}
}
else if (_start == null) {
// Create the _start field, length will change
_start = new BookmarkField();
_start.set(this.buffer, pos, end - pos);
}
}
break;
// Range separator
case (byte)':':
{
// Have to be between start and end and have started
// the _start bookmark, and not yet found separator.
if (foundClose || _open < 0 || _start == null || foundSeparator) {
notValid();
return;
}
foundSeparator = true;
// Check for setting the _start length
if (pos - _start.position < _start.length) {
_start.length = pos - _start.position;
}
}
break;
// Close of range
case (byte)')':
case (byte)']':
{
// Have have started _end
if (foundClose || _open < 0 || _end == null) {
notValid();
return;
}
foundClose = true;
length = pos - this.position + 1;
// Check for setting end length
if (pos - _end.position < _end.length) {
_end.length = pos - _end.position;
}
}
break;
// Spaces are allowed, but skipped
case (byte)' ':
{
// Is this space at the end of _end?
if (_end != null && pos - _end.position < _end.length) {
_end.length = pos - _end.position;
}
// Is this the end of _start?
else if (_start != null && pos - _start.position < _start.length) {
_start.length = pos - _start.position;
}
}
break;
default:
{
notValid();
return;
}
} // end switch
++pos;
} // end while
if (_end == null || _start == null || !foundSeparator || !foundClose || _open < 0) {
notValid();
}
}
}