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) 2011-2012 Barchart, Inc.
*
* All rights reserved. Licensed under the OSI BSD License.
*
* http://www.opensource.org/licenses/bsd-license.php
*/
package com.barchart.feed.ddf.message.provider;
import static com.barchart.util.common.ascii.ASCII.NUL;
import static com.barchart.util.common.ascii.ASCII._0_;
import static com.barchart.util.common.ascii.ASCII._A_;
import static com.barchart.util.common.ascii.ASCII._J_;
import static com.barchart.util.common.ascii.ASCII._K_;
import static com.barchart.util.common.ascii.ASCII._T_;
import static com.barchart.util.common.ascii.ASCII._Z_;
import static com.barchart.util.common.ascii.ASCII.isDigit;
import static com.barchart.util.common.ascii.ASCII.isLetterUpper;
import java.nio.ByteBuffer;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.ReadableDateTime;
import org.w3c.dom.Element;
import com.barchart.feed.ddf.message.api.DDF_MarketBook;
import com.barchart.feed.ddf.symbol.provider.DDF_Symbology;
import com.barchart.feed.ddf.util.ClockDDF;
import com.barchart.feed.ddf.util.FeedClock;
import com.barchart.feed.ddf.util.HelperDDF;
import com.barchart.feed.ddf.util.HelperXML;
import com.barchart.util.common.ascii.ASCII;
/* TODO make public ? */
public class CodecHelper {
// TODO make configurable
static final boolean IS_FEED_TIME_STAMP_PRESENT = true;
// ///////////////////////////////////////////////
/** maximum size of ddf book snapshot on bid or ask side */
final static int DDF_BOOK_LIMIT = DDF_MarketBook.ENTRY_LIMIT;
/** default ddf message delay */
static final int DDF_NO_DELAY = 0;
/** default ddf book prices */
static final long[] DDF_NO_PRICES = new long[DDF_BOOK_LIMIT];
/** default ddf book sizes */
static final long[] DDF_NO_SIZES = new long[DDF_BOOK_LIMIT];
/** */
static final DX_XS_Session[] DDF_NO_SESSIONS = new DX_XS_Session[0];
/** */
static final int DDF_NO_COUNT = 0;
/** ddf encoded time stamp first byte */
final static byte DDF_CENTURY = ASCII.DC4;
/** ddf time stamp encoding/decoding mask */
final static int DDF_TIME_STAMP_MASK = 0x40;
// ///////////////////////////////////////////////
// feed time stamp - "magic 9 bytes" or "current default"
private static final FeedClock clock = ClockDDF.clock;
static final long decodeFeedTimeStamp(final DateTimeZone zone,
final ByteBuffer buffer) {
if (buffer.position() == buffer.limit()) {
// no suffix; return current
return clock.millis();
}
//
buffer.mark();
final byte timeStampStart = buffer.get();
buffer.reset();
if (timeStampStart == DDF_CENTURY) {
// magic 9 bytes
final long time = decodeMillisUTC(zone, buffer);
/* No longer setting DDF time on every message, revert to only using
* DDF_ControlTimestamp messages for current time. This was causing
* real time data to look delayed */
// TODO This will still make delayed data look like realtime data
// clock.set(time);
return time;
} else {
// unknown suffix; return current
return clock.millis();
}
}
static final void encodeFeedTimeStamp(final long millisUTC,
final DateTimeZone zone, final ByteBuffer buffer) {
if (millisUTC == HelperDDF.DDF_EMPTY
|| millisUTC == HelperDDF.DDF_CLEAR) {
return;
}
if (IS_FEED_TIME_STAMP_PRESENT) {
CodecHelper.encodeMillisUTC(millisUTC, zone, buffer);
}
}
static final byte[] read(final ByteBuffer buffer, final byte marker) {
final byte[] source = buffer.array();
final int start = buffer.position();
int index = start;
while (index < source.length && source[index] != marker) {
index++;
}
buffer.position(index + 1);
final int size = index - start;
final byte[] target = new byte[size];
System.arraycopy(source, start, target, 0, size);
return target;
}
static final byte find(final ByteBuffer buffer, final byte marker) {
return find(buffer.array(), buffer.position(), marker);
}
static final byte find(final byte[] source, final int start,
final byte marker) {
int index = start;
while (index < source.length && source[index] != marker) {
index++;
}
if (index == start || index == source.length) {
return NUL;
} else {
return source[index - 1];
}
}
//
final static void checkDigit(final int value) {
if (value < 0 || value >= 10) {
throw new IllegalArgumentException();
}
}
final static void encodeUnsigned_1(final int value, final ByteBuffer buffer) {
checkDigit(value);
buffer.put((byte) (_0_ + value));
}
final static void encodeUnsigned_1_book(final int value,
final ByteBuffer buffer) {
if (0 <= value && value < 10) {
buffer.put((byte) (_0_ + value));
return;
}
if (10 <= value && value < (_Z_ - _A_)) {
buffer.put((byte) (_A_ + value));
return;
}
// FIXME silent error
buffer.put(_0_);
}
final static byte decodeUnsigned_1(final ByteBuffer buffer) {
final int value = buffer.get() - _0_;
checkDigit(value);
return (byte) value;
}
final static byte decodeUnsigned_1_book(final ByteBuffer buffer) {
final byte alpha = buffer.get();
if (isDigit(alpha)) {
return (byte) (alpha - _0_);
}
if (isLetterUpper(alpha)) {
return (byte) (10 + alpha - _A_);
}
// FIXME silent error
return 0;
}
final static void encodeUnsigned_2(final int value, final ByteBuffer buffer) {
if (value < 0 || value >= 100) {
throw new IllegalArgumentException();
}
final int ones = value % 10;
final int tens = value / 10;
buffer.put((byte) (_0_ + tens)); // first byte
buffer.put((byte) (_0_ + ones)); // second byte
}
final static byte decodeUnsigned_2(final ByteBuffer buffer) {
final int tens = buffer.get() - _0_;
checkDigit(tens);
final int ones = buffer.get() - _0_;
checkDigit(ones);
return (byte) (tens * 10 + ones);
}
static final int bookBidIndexFrom(final byte code) {
if (code < _K_ || _T_ < code) {
throw new IllegalArgumentException();
}
return (code - _K_);
}
static final byte bookBidCodeFrom(final int index) {
if (index < 0 || DDF_BOOK_LIMIT <= index) {
throw new IllegalArgumentException();
}
return (byte) (_K_ + index);
}
static final int bookAskIndexFrom(final byte code) {
if (code < _A_ || _J_ < code) {
throw new IllegalArgumentException();
}
return (_J_ - code);
}
static final byte bookAskCodeFrom(final int index) {
if (index < 0 || DDF_BOOK_LIMIT <= index) {
throw new IllegalArgumentException();
}
return (byte) (_J_ - index);
}
static final byte[][] xmlDecSymbol(final Element tag,
final String attribute, final boolean isThrow) {
final String string = tag.getAttribute(attribute);
if (string.length() > 0) {
try {
return DDF_Symbology.symbolArrayFromSymbolString(string);
} catch (final Exception e) {
// below
}
}
if (isThrow) {
throw new IllegalArgumentException("attribute not valid : "
+ attribute);
}
return null;
}
// byte array
static final boolean isXmlBook(final Element root) {
return HelperXML.isXmlNameMatch(root, XmlTagBook.TAG);
}
static final boolean isXmlCuvol(final Element root) {
return HelperXML.isXmlNameMatch(root, XmlTagCuvol.TAG);
}
static final boolean isXmlQuote(final Element root) {
return HelperXML.isXmlNameMatch(root, XmlTagQuote.TAG);
}
final static byte encodeTimeStampByte(final int timeField) {
return (byte) (timeField | DDF_TIME_STAMP_MASK);
}
final static int decodeTimeStampByte(final byte timeByte) {
return timeByte & (~DDF_TIME_STAMP_MASK);
}
/** time zone information is discarded */
static final void encodeTimeStamp(final ReadableDateTime dateTime,
final ByteBuffer buffer) {
// base fields
buffer.put(DDF_CENTURY); // century
buffer.put(encodeTimeStampByte(dateTime.getYearOfCentury())); // year
buffer.put(encodeTimeStampByte(dateTime.getMonthOfYear())); // month
buffer.put(encodeTimeStampByte(dateTime.getDayOfMonth())); // day
buffer.put(encodeTimeStampByte(dateTime.getHourOfDay())); // hours
buffer.put(encodeTimeStampByte(dateTime.getMinuteOfHour())); // minutes
buffer.put(encodeTimeStampByte(dateTime.getSecondOfMinute())); // seconds
// milliseconds
final int millisOfSecond = dateTime.getMillisOfSecond();
buffer.put((byte) (millisOfSecond & 0xFF)); // low byte
buffer.put((byte) ((millisOfSecond >>> 8) & 0xFF)); // high byte
}
/** time zone information is provided */
static final DateTime decodeTimeStamp(final DateTimeZone zone,
final ByteBuffer buffer) {
// base fields
buffer.get(); // DDF_CENTURY
final int yearOfEra = 2000 + decodeTimeStampByte(buffer.get());
final int monthOfYear = decodeTimeStampByte(buffer.get());
final int dayOfMonth = decodeTimeStampByte(buffer.get());
final int hourOfDay = decodeTimeStampByte(buffer.get());
final int minuteOfHour = decodeTimeStampByte(buffer.get());
final int secondOfMinute = decodeTimeStampByte(buffer.get());
// milliseconds
final byte lo = buffer.get();
final byte hi = buffer.get();
final int millisOfSecond = ((hi & 0xFF) << 8) | (lo & 0xFF);
// will throw RTE if any field is out of range
return new DateTime(//
yearOfEra, monthOfYear, dayOfMonth, //
hourOfDay, minuteOfHour, secondOfMinute, //
millisOfSecond, zone);
}
static final void encodeMillisUTC(final long millisUTC,
final DateTimeZone zone, final ByteBuffer buffer) {
final DateTime dateTime = new DateTime(millisUTC, zone);
encodeTimeStamp(dateTime, buffer);
}
static final long decodeMillisUTC(final DateTimeZone zone,
final ByteBuffer buffer) {
final DateTime dateTime = decodeTimeStamp(zone, buffer);
return dateTime.getMillis();
}
//
static final void check(final byte left, final byte right) {
if (left == right) {
return;
} else {
throw new RuntimeException("no match;" + " left=" + left
+ " right=" + right);
}
}
}