uk.co.real_logic.artio.dictionary.ir.Field Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of artio-codecs Show documentation
Show all versions of artio-codecs Show documentation
High-Performance FIX Gateway
/*
* Copyright 2015-2022 Real Logic Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package uk.co.real_logic.artio.dictionary.ir;
import org.agrona.Verify;
import uk.co.real_logic.artio.dictionary.ir.Entry.Element;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
public final class Field implements Element
{
private final int number;
private final String name;
private boolean isInParent;
private Type type;
private final List values;
// true iff you've got a shared dictionary and this field represents a type which is sometimes an enum and
// sometimes not.
private boolean hasSharedSometimesEnumClash;
private Field associatedLengthField;
public static Field registerField(
final Map nameToField,
final int number,
final String name,
final Type type)
{
final Field field = new Field(number, name, type);
nameToField.put(name, field);
return field;
}
public Field(final int number, final String name, final Type type)
{
this.number = number;
this.name = name;
this.type = type;
this.values = new ArrayList<>();
}
public Type type()
{
return type;
}
public Field associatedLengthField()
{
return associatedLengthField;
}
public void associatedLengthField(final Field associatedLengthField)
{
this.associatedLengthField = associatedLengthField;
}
public void type(final Type type)
{
Verify.notNull(type, "type");
this.type = type;
}
public String name()
{
return name;
}
public int number()
{
return number;
}
public List values()
{
return values;
}
public Field addValue(final String representation, final String description)
{
values().add(new Value(representation, description));
return this;
}
public boolean isEnum()
{
return !values.isEmpty();
}
public boolean hasSharedSometimesEnumClash()
{
return hasSharedSometimesEnumClash;
}
public void hasSharedSometimesEnumClash(final boolean hasSharedSometimesEnumClash)
{
this.hasSharedSometimesEnumClash = hasSharedSometimesEnumClash;
}
public String toString()
{
return "Field{" +
"number=" + number +
", name='" + name + '\'' +
", type=" + type +
", hasSharedSometimesEnumClash=" + hasSharedSometimesEnumClash +
", associatedLengthField=" + associatedLengthField +
", values=" + values +
'}';
}
public boolean isInParent()
{
return isInParent;
}
public void isInParent(final boolean isInParent)
{
this.isInParent = isInParent;
}
public enum Type
{
// int types
INT(false, true, false, false, false),
LENGTH(false, true, false, false, false),
SEQNUM(false, true, false, false, false),
NUMINGROUP(false, true, false, false, false),
DAYOFMONTH(false, true, false, false, false),
// Custom LONG integer type. Not supported elsewhere by FIX AFAIK
LONG(false, true, false, false, false),
// float types
FLOAT(false, false, true, false, false),
PRICE(false, false, true, false, false),
PRICEOFFSET(false, false, true, false, false),
QTY(false, false, true, false, false),
// Not standard FIX but was observed in the wild in an IB's FIX 4.2 dictonary
QUANTITY(false, false, true, false, false),
// Percentage represented as a float
PERCENTAGE(false, false, true, false, false),
// Float amount, not to be confused with boolean Y/N AMT
AMT(false, false, true, false, false),
CHAR(false, false, false, false, true),
MULTIPLECHARVALUE(true, false, false, true, false),
STRING(true, false, false, false, false),
MULTIPLEVALUESTRING(true, false, false, true, false),
MULTIPLESTRINGVALUE(true, false, false, true, false),
// Technically has extra validation but we'll just make it a String for now.
TENOR(true, false, false, true, false),
CURRENCY(true, false, false, false, false), // String using ISO 4217 (3 chars)
EXCHANGE(true, false, false, false, false), // String using ISO 10383 (2 chars)
COUNTRY(true, false, false, false, false), // String using ISO 3166
LANGUAGE(true, false, false, false, false), // String using ISO 639-1 standard
// NB: data doesn't have a length field because in specified
// XML files it often comes along with a length field.
DATA(false, false, false, false, false),
// Only used in 5.0sp1 or later.
XMLDATA(false, false, false, false, false),
// Boolean types
BOOLEAN(false, false, false, false, false),
UTCTIMESTAMP(true, false, false, false, false), // YYYYMMDD-HH:MM:SS or YYYYMMDD-HH:MM:SS.sss
UTCTIMEONLY(true, false, false, false, false), // HH:MM:SS or HH:MM:SS.sss
UTCDATEONLY(true, false, false, false, false), // YYYYMMDD
LOCALMKTDATE(true, false, false, false, false), // YYYYMMDD
MONTHYEAR(true, false, false, false, false), // YYYYMM or YYYYMMDD or YYYYMMWW
TZTIMEONLY(true, false, false, false, false), // HH:MM[:SS][Z [ + - hh[:mm]]]
TZTIMESTAMP(true, false, false, false, false); // YYYYMMDD-HH:MM:SS.sss*[Z [ + - hh[:mm]]]
private final boolean isStringBased;
private final boolean isIntBased;
private final boolean isFloatBased;
private final boolean isMultiValue;
private final boolean isCharBased;
Type(
final boolean isStringBased,
final boolean isIntBased,
final boolean isFloatBased,
final boolean isMultiValue,
final boolean isCharBased
)
{
this.isStringBased = isStringBased;
this.isIntBased = isIntBased;
this.isFloatBased = isFloatBased;
this.isMultiValue = isMultiValue;
this.isCharBased = isCharBased;
}
public boolean isStringBased()
{
return isStringBased;
}
public boolean isIntBased()
{
return isIntBased;
}
public boolean isFloatBased()
{
return isFloatBased;
}
public boolean isCharBased()
{
return isCharBased;
}
public boolean isDataBased()
{
return this == DATA || this == XMLDATA;
}
public boolean hasOffsetField(final boolean flyweightsEnabled)
{
return hasLengthField(flyweightsEnabled) || (flyweightsEnabled && isDataBased());
}
public boolean hasLengthField(final boolean flyweightsEnabled)
{
return flyweightsEnabled ?
isStringBased() || isIntBased() || isFloatBased() :
isStringBased();
}
public boolean isMultiValue()
{
return isMultiValue;
}
public static Type lookup(final String name)
{
// Renamed from FIX 4.2 to Fix 4.4 spec
if ("UTCDATE".equals(name))
{
return UTCDATEONLY;
}
// Fix typo in bad dictionary
if ("STIRNG".equals(name))
{
return STRING;
}
// Standardise naming from bad dictionaries
if ("MONTH-YEAR".equals(name))
{
return MONTHYEAR;
}
if ("RATE".equals(name))
{
return PRICE;
}
return valueOf(name.trim());
}
}
public static class Value
{
private final String representation;
private final String description;
private List alternativeNames;
public Value(final String representation, final String description)
{
this.representation = representation;
this.description = description;
}
public String representation()
{
return representation;
}
public String description()
{
return description;
}
public boolean equals(final Object o)
{
if (o == null || getClass() != o.getClass())
{
return false;
}
final Value value = (Value)o;
return Objects.equals(representation, value.representation) &&
Objects.equals(description, value.description);
}
public int hashCode()
{
int result = representation.hashCode();
result = 31 * result + (description != null ? description.hashCode() : 0);
return result;
}
public List alternativeNames()
{
return alternativeNames;
}
public void alternativeNames(final List alternativeNames)
{
this.alternativeNames = alternativeNames;
}
public String toString()
{
return "Value{" +
"representation=" + representation +
", description='" + description + '\'' +
", alternativeNames='" + alternativeNames + '\'' +
'}';
}
}
}