/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.financial.analytics.fudgemsg; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang.ArrayUtils; import org.fudgemsg.FudgeField; import org.fudgemsg.FudgeMsg; import org.fudgemsg.MutableFudgeMsg; import org.fudgemsg.mapping.FudgeBuilderFor; import org.fudgemsg.mapping.FudgeDeserializer; import org.fudgemsg.mapping.FudgeSerializer; import org.fudgemsg.types.FudgeDate; import org.threeten.bp.LocalDate; import org.threeten.bp.Period; import com.google.common.primitives.Doubles; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.financial.analytics.CurrencyLabelledMatrix1D; import com.opengamma.financial.analytics.DoubleLabelledMatrix1D; import com.opengamma.financial.analytics.LocalDateLabelledMatrix1D; import com.opengamma.financial.analytics.StringLabelledMatrix1D; import com.opengamma.financial.analytics.TenorLabelledLocalDateDoubleTimeSeriesMatrix1D; import com.opengamma.financial.analytics.TenorLabelledMatrix1D; import com.opengamma.timeseries.date.localdate.LocalDateDoubleTimeSeries; import com.opengamma.util.ClassUtils; import com.opengamma.util.money.Currency; import com.opengamma.util.time.Tenor; /** * */ final class LabelledMatrix1DBuilder { /** Field name. */ private static final String MATRIX_FIELD_NAME = "matrix"; private static final String LABELS_TITLE_FIELD_NAME = "labelsTitle"; private static final String VALUES_TITLE_FIELD_NAME = "valuesTitle"; private static final int LABEL_TYPE_ORDINAL = 0; private static final int KEY_ORDINAL = 1; private static final int LABEL_ORDINAL = 2; private static final int VALUE_ORDINAL = 3; private LabelledMatrix1DBuilder() { } private static Class<?> getLabelClass(final String labelType, final Map<String, Class<?>> loadedClasses) throws ClassNotFoundException { Class<?> labelClass; labelClass = loadedClasses.get(labelType); if (labelClass == null) { labelClass = ClassUtils.loadClass(labelType); loadedClasses.put(labelType, labelClass); } return labelClass; } @FudgeBuilderFor(DoubleLabelledMatrix1D.class) public static final class DoubleLabelledMatrix1DFudgeBuilder extends AbstractFudgeBuilder<DoubleLabelledMatrix1D> { @Override protected void buildMessage(final FudgeSerializer serializer, final MutableFudgeMsg message, final DoubleLabelledMatrix1D object) { final MutableFudgeMsg msg = serializer.newMessage(); final Double[] keys = object.getKeys(); final Object[] labels = object.getLabels(); final double[] values = object.getValues(); for (int i = 0; i < object.size(); i++) { msg.add(LABEL_TYPE_ORDINAL, labels[i].getClass().getName()); msg.add(KEY_ORDINAL, keys[i]); serializer.addToMessage(msg, null, LABEL_ORDINAL, labels[i]); msg.add(VALUE_ORDINAL, values[i]); } message.add(MATRIX_FIELD_NAME, msg); if (object.getLabelsTitle() != null) { message.add(LABELS_TITLE_FIELD_NAME, object.getLabelsTitle()); } if (object.getValuesTitle() != null) { message.add(VALUES_TITLE_FIELD_NAME, object.getValuesTitle()); } } @SuppressWarnings("synthetic-access") @Override public DoubleLabelledMatrix1D buildObject(final FudgeDeserializer deserializer, final FudgeMsg message) { final FudgeMsg msg = message.getMessage(MATRIX_FIELD_NAME); final Queue<String> labelTypes = new LinkedList<>(); final Queue<FudgeField> labelValues = new LinkedList<>(); final List<Double> keys = new LinkedList<>(); final List<Object> labels = new LinkedList<>(); final List<Double> values = new LinkedList<>(); for (final FudgeField field : msg) { switch (field.getOrdinal()) { case LABEL_TYPE_ORDINAL: labelTypes.add((String) field.getValue()); break; case KEY_ORDINAL: keys.add((Double) field.getValue()); break; case LABEL_ORDINAL: labelValues.add(field); break; case VALUE_ORDINAL: values.add((Double) field.getValue()); break; } if (!labelTypes.isEmpty() && !labelValues.isEmpty()) { // Have a type and a value, which can be consumed final String labelType = labelTypes.remove(); Class<?> labelClass; try { labelClass = getLabelClass(labelType, _loadedClasses); } catch (final ClassNotFoundException ex) { throw new OpenGammaRuntimeException("Could not deserialize label of type " + labelType, ex); } final FudgeField labelValue = labelValues.remove(); final Object label = deserializer.fieldValueToObject(labelClass, labelValue); labels.add(label); } } final String labelsTitle = message.getString(LABELS_TITLE_FIELD_NAME); final String valuesTitle = message.getString(VALUES_TITLE_FIELD_NAME); final int matrixSize = keys.size(); final Double[] keysArray = new Double[matrixSize]; keys.toArray(keysArray); final Object[] labelsArray = new Object[matrixSize]; labels.toArray(labelsArray); final double[] valuesArray = Doubles.toArray(values); return new DoubleLabelledMatrix1D(keysArray, labelsArray, labelsTitle, valuesArray, valuesTitle); } private final Map<String, Class<?>> _loadedClasses = new ConcurrentHashMap<>(); //TODO: This should be expired at some point, but it's an insignificant leak at the moment } @FudgeBuilderFor(LocalDateLabelledMatrix1D.class) public static final class LocalDateLabelledMatrix1DBuilder extends AbstractFudgeBuilder<LocalDateLabelledMatrix1D> { @Override protected void buildMessage(final FudgeSerializer serializer, final MutableFudgeMsg message, final LocalDateLabelledMatrix1D object) { final MutableFudgeMsg msg = serializer.newMessage(); final LocalDate[] keys = object.getKeys(); final Object[] labels = object.getLabels(); final double[] values = object.getValues(); for (int i = 0; i < object.size(); i++) { msg.add(LABEL_TYPE_ORDINAL, labels[i].getClass().getName()); msg.add(KEY_ORDINAL, keys[i]); serializer.addToMessage(msg, null, LABEL_ORDINAL, labels[i]); msg.add(VALUE_ORDINAL, values[i]); } message.add(MATRIX_FIELD_NAME, msg); if (object.getLabelsTitle() != null) { message.add(LABELS_TITLE_FIELD_NAME, object.getLabelsTitle()); } if (object.getValuesTitle() != null) { message.add(VALUES_TITLE_FIELD_NAME, object.getValuesTitle()); } } @Override public LocalDateLabelledMatrix1D buildObject(final FudgeDeserializer deserializer, final FudgeMsg message) { final FudgeMsg msg = message.getMessage(MATRIX_FIELD_NAME); final Queue<String> labelTypes = new LinkedList<>(); final Queue<FudgeField> labelValues = new LinkedList<>(); final List<LocalDate> keys = new LinkedList<>(); final List<Object> labels = new LinkedList<>(); final List<Double> values = new LinkedList<>(); for (final FudgeField field : msg) { switch (field.getOrdinal()) { case LABEL_TYPE_ORDINAL: labelTypes.add((String) field.getValue()); break; case KEY_ORDINAL: keys.add(((FudgeDate) field.getValue()).toLocalDate()); break; case LABEL_ORDINAL: labelValues.add(field); break; case VALUE_ORDINAL: values.add((Double) field.getValue()); break; } if (!labelTypes.isEmpty() && !labelValues.isEmpty()) { // Have a type and a value, which can be consumed final String labelType = labelTypes.remove(); final Class<?> labelClass = getClass(labelType); final FudgeField labelValue = labelValues.remove(); final Object label = deserializer.fieldValueToObject(labelClass, labelValue); labels.add(label); } } final String labelsTitle = message.getString(LABELS_TITLE_FIELD_NAME); final String valuesTitle = message.getString(VALUES_TITLE_FIELD_NAME); final int matrixSize = keys.size(); final LocalDate[] keysArray = new LocalDate[matrixSize]; keys.toArray(keysArray); final Object[] labelsArray = new Object[matrixSize]; labels.toArray(labelsArray); final double[] valuesArray = Doubles.toArray(values); return new LocalDateLabelledMatrix1D(keysArray, labelsArray, labelsTitle, valuesArray, valuesTitle); } @SuppressWarnings("synthetic-access") private Class<?> getClass(final String labelType) { Class<?> labelClass; try { labelClass = LabelledMatrix1DBuilder.getLabelClass(labelType, _loadedClasses); } catch (final ClassNotFoundException ex) { throw new OpenGammaRuntimeException("Could not deserialize label of type " + labelType, ex); } return labelClass; } private final Map<String, Class<?>> _loadedClasses = new ConcurrentHashMap<>(); //TODO: This should be expired at some point, but it's an insignificant leak at the moment } @FudgeBuilderFor(TenorLabelledMatrix1D.class) public static final class TenorLabelledMatrix1DBuilder extends AbstractFudgeBuilder<TenorLabelledMatrix1D> { @Override protected void buildMessage(final FudgeSerializer serializer, final MutableFudgeMsg message, final TenorLabelledMatrix1D object) { final MutableFudgeMsg msg = serializer.newMessage(); final Tenor[] keys = object.getKeys(); final Object[] labels = object.getLabels(); final double[] values = object.getValues(); for (int i = 0; i < object.size(); i++) { msg.add(LABEL_TYPE_ORDINAL, labels[i].getClass().getName()); msg.add(KEY_ORDINAL, keys[i]); serializer.addToMessage(msg, null, LABEL_ORDINAL, labels[i]); msg.add(VALUE_ORDINAL, values[i]); } message.add(MATRIX_FIELD_NAME, msg); if (object.getLabelsTitle() != null) { message.add(LABELS_TITLE_FIELD_NAME, object.getLabelsTitle()); } if (object.getValuesTitle() != null) { message.add(VALUES_TITLE_FIELD_NAME, object.getValuesTitle()); } } @Override public TenorLabelledMatrix1D buildObject(final FudgeDeserializer deserializer, final FudgeMsg message) { final FudgeMsg msg = message.getMessage(MATRIX_FIELD_NAME); final Queue<String> labelTypes = new LinkedList<>(); final Queue<FudgeField> labelValues = new LinkedList<>(); final List<Tenor> keys = new LinkedList<>(); final List<Object> labels = new LinkedList<>(); final List<Double> values = new LinkedList<>(); for (final FudgeField field : msg) { switch (field.getOrdinal()) { case LABEL_TYPE_ORDINAL: labelTypes.add((String) field.getValue()); break; case KEY_ORDINAL: keys.add(Tenor.of(Period.parse((String) field.getValue()))); break; case LABEL_ORDINAL: labelValues.add(field); break; case VALUE_ORDINAL: values.add((Double) field.getValue()); break; } if (!labelTypes.isEmpty() && !labelValues.isEmpty()) { // Have a type and a value, which can be consumed final String labelType = labelTypes.remove(); final Class<?> labelClass = getClass(labelType); final FudgeField labelValue = labelValues.remove(); final Object label = deserializer.fieldValueToObject(labelClass, labelValue); labels.add(label); } } final String labelsTitle = message.getString(LABELS_TITLE_FIELD_NAME); final String valuesTitle = message.getString(VALUES_TITLE_FIELD_NAME); final int matrixSize = keys.size(); final Tenor[] keysArray = new Tenor[matrixSize]; keys.toArray(keysArray); final Object[] labelsArray = new Object[matrixSize]; labels.toArray(labelsArray); final double[] valuesArray = Doubles.toArray(values); return new TenorLabelledMatrix1D(keysArray, labelsArray, labelsTitle, valuesArray, valuesTitle); } @SuppressWarnings("synthetic-access") private Class<?> getClass(final String labelType) { Class<?> labelClass; try { labelClass = LabelledMatrix1DBuilder.getLabelClass(labelType, _loadedClasses); } catch (final ClassNotFoundException ex) { throw new OpenGammaRuntimeException("Could not deserialize label of type " + labelType, ex); } return labelClass; } private final Map<String, Class<?>> _loadedClasses = new ConcurrentHashMap<>(); //TODO: This should be expired at some point, but it's an insignificant leak at the moment } //TODO add ZonedDateTime version @FudgeBuilderFor(CurrencyLabelledMatrix1D.class) public static final class CurrencyLabelledMatrix1DBuilder extends AbstractFudgeBuilder<CurrencyLabelledMatrix1D> { @Override protected void buildMessage(final FudgeSerializer serializer, final MutableFudgeMsg message, final CurrencyLabelledMatrix1D object) { final MutableFudgeMsg msg = serializer.newMessage(); final Currency[] keys = object.getKeys(); final Object[] labels = object.getLabels(); final double[] values = object.getValues(); for (int i = 0; i < object.size(); i++) { msg.add(LABEL_TYPE_ORDINAL, labels[i].getClass().getName()); msg.add(KEY_ORDINAL, keys[i]); serializer.addToMessage(msg, null, LABEL_ORDINAL, labels[i]); msg.add(VALUE_ORDINAL, values[i]); } message.add(MATRIX_FIELD_NAME, msg); if (object.getLabelsTitle() != null) { message.add(LABELS_TITLE_FIELD_NAME, object.getLabelsTitle()); } if (object.getValuesTitle() != null) { message.add(VALUES_TITLE_FIELD_NAME, object.getValuesTitle()); } } @SuppressWarnings("synthetic-access") @Override public CurrencyLabelledMatrix1D buildObject(final FudgeDeserializer deserializer, final FudgeMsg message) { final FudgeMsg msg = message.getMessage(MATRIX_FIELD_NAME); final Queue<String> labelTypes = new LinkedList<>(); final Queue<FudgeField> labelValues = new LinkedList<>(); final List<Currency> keys = new LinkedList<>(); final List<Object> labels = new LinkedList<>(); final List<Double> values = new LinkedList<>(); for (final FudgeField field : msg) { switch (field.getOrdinal()) { case LABEL_TYPE_ORDINAL: labelTypes.add((String) field.getValue()); break; case KEY_ORDINAL: keys.add(Currency.of((String) field.getValue())); break; case LABEL_ORDINAL: labelValues.add(field); break; case VALUE_ORDINAL: values.add((Double) field.getValue()); break; } if (!labelTypes.isEmpty() && !labelValues.isEmpty()) { // Have a type and a value, which can be consumed final String labelType = labelTypes.remove(); Class<?> labelClass; try { labelClass = LabelledMatrix1DBuilder.getLabelClass(labelType, _loadedClasses); } catch (final ClassNotFoundException ex) { throw new OpenGammaRuntimeException("Could not deserialize label of type " + labelType, ex); } final FudgeField labelValue = labelValues.remove(); final Object label = deserializer.fieldValueToObject(labelClass, labelValue); // labels.add(Currency.of((String) label)); labels.add(label); } } final String labelsTitle = message.getString(LABELS_TITLE_FIELD_NAME); final String valuesTitle = message.getString(VALUES_TITLE_FIELD_NAME); final int matrixSize = keys.size(); final Currency[] keysArray = new Currency[matrixSize]; keys.toArray(keysArray); final Object[] labelsArray = new Object[matrixSize]; labels.toArray(labelsArray); final double[] valuesArray = Doubles.toArray(values); return new CurrencyLabelledMatrix1D(keysArray, labelsArray, labelsTitle, valuesArray, valuesTitle); } private final Map<String, Class<?>> _loadedClasses = new ConcurrentHashMap<>(); //TODO: This should be expired at some point, but it's an insignificant leak at the moment } @FudgeBuilderFor(StringLabelledMatrix1D.class) public static final class StringLabelledMatrix1DBuilder extends AbstractFudgeBuilder<StringLabelledMatrix1D> { @Override protected void buildMessage(final FudgeSerializer serializer, final MutableFudgeMsg message, final StringLabelledMatrix1D object) { final MutableFudgeMsg msg = serializer.newMessage(); final String[] keys = object.getKeys(); final double[] values = object.getValues(); for (int i = 0; i < object.size(); i++) { msg.add(KEY_ORDINAL, keys[i]); msg.add(VALUE_ORDINAL, values[i]); } message.add(MATRIX_FIELD_NAME, msg); if (object.getLabelsTitle() != null) { message.add(LABELS_TITLE_FIELD_NAME, object.getLabelsTitle()); } if (object.getValuesTitle() != null) { message.add(VALUES_TITLE_FIELD_NAME, object.getValuesTitle()); } } @Override public StringLabelledMatrix1D buildObject(final FudgeDeserializer deserializer, final FudgeMsg message) { final FudgeMsg msg = message.getMessage(MATRIX_FIELD_NAME); final List<String> keys = new LinkedList<>(); final List<Double> values = new LinkedList<>(); for (final FudgeField field : msg) { switch (field.getOrdinal()) { case KEY_ORDINAL: keys.add((String) field.getValue()); break; case VALUE_ORDINAL: values.add((Double) field.getValue()); break; } } final String labelsTitle = message.getString(LABELS_TITLE_FIELD_NAME); final String valuesTitle = message.getString(VALUES_TITLE_FIELD_NAME); final String[] keysArray = keys.toArray(ArrayUtils.EMPTY_STRING_ARRAY); final double[] valuesArray = Doubles.toArray(values); return new StringLabelledMatrix1D(keysArray, keysArray, labelsTitle, valuesArray, valuesTitle); } } @FudgeBuilderFor(TenorLabelledLocalDateDoubleTimeSeriesMatrix1D.class) public static final class TenorLabelledLocalDateDoubleTimeSeriesMatrix1DFudgeBuilder extends AbstractFudgeBuilder<TenorLabelledLocalDateDoubleTimeSeriesMatrix1D> { @Override protected void buildMessage(final FudgeSerializer serializer, final MutableFudgeMsg message, final TenorLabelledLocalDateDoubleTimeSeriesMatrix1D object) { final MutableFudgeMsg msg = serializer.newMessage(); final Tenor[] keys = object.getKeys(); final Object[] labels = object.getLabels(); final LocalDateDoubleTimeSeries[] values = object.getValues(); for (int i = 0; i < object.size(); i++) { msg.add(LABEL_TYPE_ORDINAL, labels[i].getClass().getName()); msg.add(KEY_ORDINAL, keys[i]); serializer.addToMessage(msg, null, LABEL_ORDINAL, labels[i]); serializer.addToMessage(msg, null, VALUE_ORDINAL, values[i]); } message.add(MATRIX_FIELD_NAME, msg); if (object.getLabelsTitle() != null) { message.add(LABELS_TITLE_FIELD_NAME, object.getLabelsTitle()); } if (object.getValuesTitle() != null) { message.add(VALUES_TITLE_FIELD_NAME, object.getValuesTitle()); } } @Override public TenorLabelledLocalDateDoubleTimeSeriesMatrix1D buildObject(final FudgeDeserializer deserializer, final FudgeMsg message) { final FudgeMsg msg = message.getMessage(MATRIX_FIELD_NAME); final Queue<String> labelTypes = new LinkedList<>(); final Queue<FudgeField> labelValues = new LinkedList<>(); final List<Tenor> keys = new LinkedList<>(); final List<Object> labels = new LinkedList<>(); final List<LocalDateDoubleTimeSeries> values = new LinkedList<>(); for (final FudgeField field : msg) { switch (field.getOrdinal()) { case LABEL_TYPE_ORDINAL: labelTypes.add((String) field.getValue()); break; case KEY_ORDINAL: keys.add(Tenor.of(Period.parse((String) field.getValue()))); break; case LABEL_ORDINAL: labelValues.add(field); break; case VALUE_ORDINAL: values.add(deserializer.fieldValueToObject(LocalDateDoubleTimeSeries.class, field)); break; } if (!labelTypes.isEmpty() && !labelValues.isEmpty()) { // Have a type and a value, which can be consumed final String labelType = labelTypes.remove(); final Class<?> labelClass = getClass(labelType); final FudgeField labelValue = labelValues.remove(); final Object label = deserializer.fieldValueToObject(labelClass, labelValue); labels.add(label); } } final String labelsTitle = message.getString(LABELS_TITLE_FIELD_NAME); final String valuesTitle = message.getString(VALUES_TITLE_FIELD_NAME); final int matrixSize = keys.size(); final Tenor[] keysArray = new Tenor[matrixSize]; keys.toArray(keysArray); final Object[] labelsArray = new Object[matrixSize]; labels.toArray(labelsArray); final LocalDateDoubleTimeSeries[] valuesArray = new LocalDateDoubleTimeSeries[matrixSize]; values.toArray(valuesArray); return new TenorLabelledLocalDateDoubleTimeSeriesMatrix1D(keysArray, labelsArray, labelsTitle, valuesArray, valuesTitle); } @SuppressWarnings("synthetic-access") private Class<?> getClass(final String labelType) { Class<?> labelClass; try { labelClass = LabelledMatrix1DBuilder.getLabelClass(labelType, _loadedClasses); } catch (final ClassNotFoundException ex) { throw new OpenGammaRuntimeException("Could not deserialize label of type " + labelType, ex); } return labelClass; } private final Map<String, Class<?>> _loadedClasses = new ConcurrentHashMap<>(); //TODO: This should be expired at some point, but it's an insignificant leak at the moment } }