/// <summary> /// The ResolveGroupReference function resolves a group /// reference against the information in the dictionary. /// </summary> /// <param name="reference"> /// The group reference to resolve. /// </param> /// <returns> /// An instance of FixDxResolvedGroup that contains all of /// the resolved information about the group. /// </returns> private FixDxResolvedGroup ResolveGroupReference(FixDxGroupReference reference) { if (string.IsNullOrEmpty(reference.Name)) { string error = "The supplied group reference's name is null or empty."; throw new ArgumentException(error); } else { if (!_mapFieldsByName.ContainsKey(reference.Name)) { string error = string.Format("Repeating group {0}'s field couldn't be resolved.", reference.Name); throw new ArgumentException(error); } else { FixDxField dxField = _mapFieldsByName[reference.Name]; FixDxResolvedGroup result = new FixDxResolvedGroup(dxField.Tag, dxField.Name, reference.Required); foreach (IFixDxElement element in Resolve(reference.Elements)) { result.Elements.Add(element); } return(result); } } }
/// <summary> /// The ExportFields method is invoked to convert all of /// the field elements in an instance of a VersaFix data /// dictionary into corresponding entries in an instance /// of an XML representation of a QuickFix dictionary. /// </summary> /// <param name="src"> /// The source dictionary for the field definitions. /// </param> /// <param name="dst"> /// The target dictionary for the field definitions. /// </param> private void ExportFields(FixDictionary src, XmlQfxDictionary dst) { foreach (IFixDxElement dxElement in src.Fields) { FixDxField dxField = dxElement as FixDxField; if (dxField != null) { XmlQfxField xmlField = new XmlQfxField(); xmlField.Name = dxField.Name; xmlField.Number = dxField.Tag.ToString(); xmlField.Type = dxField.Type; // REC: QuickFix stores the enumerators for each // field inside the field definition, so we have // to check if there is an enumeration associated // with this field and add the enumeration to the // field definition if one is found: FixDxEnumeration dxEnum = src.Enums.GetElement(dxField.Name) as FixDxEnumeration; if (dxEnum != null) { foreach (FixDxEnumerator dxEnumerator in dxEnum.Enumerators) { XmlQfxFieldEnumerator xmlEnumerator = new XmlQfxFieldEnumerator(); xmlEnumerator.Enum = dxEnumerator.Value; xmlEnumerator.Description = dxEnumerator.Description; xmlField.Enumeration.Add(xmlEnumerator); } } dst.Fields.Add(xmlField); } } }
/// <summary> /// The CloneField method creates a copy of an instance /// of a dictionary field entry. /// </summary> /// <param name="source"> /// The dictionary field entry to duplicate. /// </param> /// <returns> /// The resulting clone of the supplied element. /// </returns> private FixDxField CloneField(FixDxField source) { FixDxField result = new FixDxField(source.Tag, source.Name, source.Type); result.Enumeration = source.Enumeration; result.LengthCoded = source.LengthCoded; result.LengthField = source.LengthField; return(result); }
/// <summary> /// The ResolveFieldName function resolves a field reference /// against the information in the dictionary. /// </summary> /// <param name="reference"> /// The field reference to resolve. /// </param> /// <returns> /// An instance of FixDxResolvedField that contains all of /// the resolved information about the field. /// </returns> private FixDxResolvedField ResolveFieldReference(FixDxFieldReference reference) { if (string.IsNullOrEmpty(reference.Name)) { string error = "The supplied field reference has an empty or null name."; throw new ArgumentException(error); } else { if (!_mapFieldsByName.ContainsKey(reference.Name)) { string error = string.Format("The field reference {0} could not be resolved!", reference.Name); throw new ArgumentException(error); } else { FixDxField dxField = _mapFieldsByName[reference.Name]; if (dxField.LengthCoded == false) { FixDxResolvedField result = new FixDxResolvedField(dxField.Tag, dxField.Name, dxField.Type, reference.Required); return(result); } else { // REC: The field is length encoded, so the field that // contains the content length for this field also has // to be resolved from the dictionary: if (_mapFieldsByName.ContainsKey(dxField.LengthField)) { FixDxField dxLength = _mapFieldsByName[dxField.LengthField]; FixDxResolvedField result = new FixDxResolvedField(dxField.Tag, dxField.Name, dxField.Type, dxLength.Tag, reference.Required); return(result); } else { string error = string.Format("The field reference {0}'s length field {1} couldn't be resolved!", dxField.Name, dxField.LengthField); throw new ArgumentException(error); } } } } }
/// <summary> /// The PopulateFields method is invoked to convert all of /// the FIX field definitions in an instance of a QuickFix /// dictionary into their corresponding representations as /// elements of a VersaFix dictionary. /// </summary> /// <param name="src"> /// The XML representation of a QuickFix dictionary that the /// fields are to be copied from. /// </param> /// <param name="dst"> /// The VersaFix data dictionary that the field definitions /// are to be copied into. /// </param> private void PopulateFields(XmlQfxDictionary src, FixDictionary dst) { foreach (object field in src.Fields) { XmlQfxField xmlField = field as XmlQfxField; if (xmlField != null) { if (!string.IsNullOrEmpty(xmlField.Name)) { if (!string.IsNullOrEmpty(xmlField.Number)) { int nTag = int.Parse(xmlField.Number); FixDxField dxField = new FixDxField(nTag, xmlField.Name); // REC: Determine if there's an enumeration that corresponds // to the name of this field: if (dst.Enums.GetElement(xmlField.Name) != null) { // REC: If an enumeration exists for this field // then assign it to the VersaFix field: dxField.Enumeration = xmlField.Name; } // REC: Assign the field's data type directly // from the data type in the QuickFix field. dxField.Type = xmlField.Type; dst.Fields.Add(dxField); // REC: The QuickFix dictionaries do not provide // a separate section for data types, so we need // to just copy the data type directly from each // of the QuickFix fields into the data types of // the VersaFix dictionary: if (!string.IsNullOrEmpty(xmlField.Type)) { IFixDxElement exists = dst.DataTypes.GetElement(xmlField.Type); if (exists == null) { dst.DataTypes.Add(new FixDxDataType(xmlField.Type)); } } } } } } }
/// <summary> /// The PopulateFields method populates the fields section /// of the supplied VFX dictionary with all of the fields /// that are found in the supplied XML dictionary. /// </summary> /// <param name="source"> /// The source dictionary for the field elements. /// </param> /// <param name="target"> /// The target dictionary for the converted elements. /// </param> private static void PopulateFields(XmlDictionary source, FixDictionary target) { foreach (XmlFixDxField src in source.Fields.Entries) { if (src.LengthField == null) { FixDxField dst = new FixDxField(src.Tag, src.Name, src.Type); dst.Enumeration = src.Enumeration; target.AddField(dst); } else { FixDxField dst = new FixDxField(src.Tag, src.Name, src.Type, src.LengthField); dst.Enumeration = src.Enumeration; target.AddField(dst); } } }
/// <summary> /// The AddField method attempts to add an instance of /// a FIX field definition to the dictionary. If there /// is already an entry in the dictionary that has the /// same identifying criteria the ArgumentException is /// thrown and the method fails; It's not possible for /// the dictionary to replace a redundant field, since /// there may be an entry in the name-based index that /// corresponds to a field with a *different* tag. /// </summary> /// <param name="dxField"> /// The FIX field definition that is to be added. /// </param> public void AddField(FixDxField dxField) { if (_mapFieldsByTag.ContainsKey(dxField.Tag)) { string error = string.Format("Dictionary already contains a field with tag {0}.", dxField.Tag); throw new ArgumentException(error); } if (_mapFieldsByName.ContainsKey(dxField.Name)) { string error = string.Format("Dictionary already contains a field named {0}.", dxField.Name); throw new ArgumentException(error); } _mapFieldsByTag.Add(dxField.Tag, dxField); _mapFieldsByName.Add(dxField.Name, dxField); _fields.Add(dxField); _fldElements.Add(dxField); }
/// <summary> /// The CloneField method creates a copy of an instance /// of a dictionary field entry. /// </summary> /// <param name="source"> /// The dictionary field entry to duplicate. /// </param> /// <returns> /// The resulting clone of the supplied element. /// </returns> private FixDxField CloneField(FixDxField source) { FixDxField result = new FixDxField(source.Tag, source.Name, source.Type); result.Enumeration = source.Enumeration; result.LengthCoded = source.LengthCoded; result.LengthField = source.LengthField; return result; }
/// <summary> /// The Resolve method attempts to resolve all of the /// element references in a collection to the entries /// that correspond to them. /// </summary> /// <param name="elements"> /// The collection of dictionary elements to resolve. /// </param> /// <returns> /// The resulting collection of resolved elements. /// </returns> /// <exception cref="ArgumentException"> /// Thrown if any elements in the collection that is /// supplied to the method cannot be resolved. /// </exception> public FixDxCollection Resolve(FixDxCollection elements) { FixDxCollection result = new FixDxCollection(); // REC: Iterate over all of the elements in the collection // and determine how to resolve each of them: foreach (IFixDxElement dxElement in elements) { if (dxElement is FixDxFieldReference) { FixDxFieldReference fieldReference = dxElement as FixDxFieldReference; result.Add(ResolveFieldReference(fieldReference)); } else if (dxElement is FixDxGroupReference) { FixDxGroupReference groupReference = dxElement as FixDxGroupReference; result.Add(ResolveGroupReference(groupReference)); } else if (dxElement is FixDxBlockReference) { FixDxBlockReference blockReference = dxElement as FixDxBlockReference; // REC: Determine what type of block the reference // is referring to (component or repeating): if (string.IsNullOrEmpty(blockReference.Name)) { string error = "The supplied block reference's name is null or empty."; throw new ArgumentException(error); } else if (!_mapBlocksByName.ContainsKey(blockReference.Name)) { string error = string.Format("The block reference {0} couldn't be resolved.", blockReference.Name); throw new ArgumentException(error); } else { FixDxBlock dxBlock = _mapBlocksByName[blockReference.Name]; if (dxBlock.Type == FixDxBlockTypes.Component) { foreach (IFixDxElement element in Resolve(Expand(dxBlock.Elements))) { result.Add(element); } } else if (dxBlock.Type == FixDxBlockTypes.Repeating) { // REC: Attempt to resolve the field that the repeating // block references as the start field for the group: if (string.IsNullOrEmpty(dxBlock.Field)) { string error = string.Format("Repeating Block {0}'s start field is null or empty.", dxBlock.Field); throw new ArgumentException(error); } else if (!_mapFieldsByName.ContainsKey(dxBlock.Field)) { string error = string.Format("Repeating block {0}'s start field can't be resolved.", dxBlock.Field); throw new ArgumentException(error); } else { FixDxField dxField = _mapFieldsByName[dxBlock.Field]; FixDxResolvedGroup dxGroup = new FixDxResolvedGroup(dxField.Tag, dxField.Name, false); foreach (IFixDxElement element in Resolve(Expand(dxBlock.Elements))) { dxGroup.Elements.Add(element); } result.Add(dxGroup); } } } } } // REC: Patch from RC - sanity check all elements in the result // to ensure that there are no unresolved references. foreach (IFixDxElement e in result) { if (e is FixDxFieldReference || e is FixDxGroupReference || e is FixDxFieldReference) { throw new Exception("unresolved references exist in the resolved collection"); } } return(result); }