Package com.opengamma.financial.analytics.fudgemsg

Source Code of com.opengamma.financial.analytics.fudgemsg.LabelledMatrix3DFudgeBuilder

/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.fudgemsg;

import java.lang.reflect.Array;
import java.util.Iterator;

import org.fudgemsg.FudgeField;
import org.fudgemsg.FudgeFieldType;
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.SecondaryFieldType;
import org.fudgemsg.wire.types.FudgeWireType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.opengamma.financial.analytics.DoubleLabelledMatrix3D;
import com.opengamma.financial.analytics.LabelledMatrix3D;
import com.opengamma.util.ClassUtils;

/**
* Base class for builders of {@link LabelledMatrix3D} subclasses. Basic message structure is:
* <dl>
* <dd>[X|Y|Z]_KEYS</dd>
* <dt>The values of the keys. The default encoding is a sub-message containing the keys as anonymous fields, but if the keys are primitive types it may use one of the built-in Fudge array types.</dt>
* <dd>[X|Y|Z]_LABELS</dd>
* <dt>The values of the labels as a sub-message containing an anonymous field for each value.</dt>
* <dd>[X|Y|Z]_TYPES</dd>
* <dt>Additional type information for the labels as a sub-message containing an anonymous field for each value in <code>?_LABELS</code>. If a numeric value, this is the Fudge type identifier of the
* original value. If a string value, this is a class name of the original type. This is an optional field. If omitted, default types will be inferred from <code>?_LABELS</code>. It will only be
* generated if the inferred types differ from the actual types.</dt>
* <dd>VALUES</dd>
* <dt>A flattened array of matrix data, e.g. <code>{ { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } }</code> becomes <code>{ 1, 2, 3, 4, 5, 6, 7, 8 }</code>.</dt>
*
* @param <KX> X key type
* @param <KY> Y key type
* @param <KZ> Z key type
* @param <T> sub-type of matrix to build
*/
public abstract class LabelledMatrix3DFudgeBuilder<KX, KY, KZ, T extends LabelledMatrix3D<KX, KY, KZ, ?, ?, ?, T>> extends AbstractFudgeBuilder<T> {

  private static final Logger s_logger = LoggerFactory.getLogger(LabelledMatrix3DFudgeBuilder.class);

  /** Field name. */
  public static final String X_KEYS_KEY = "X_KEYS";
  /** Field name. */
  public static final String Y_KEYS_KEY = "Y_KEYS";
  /** Field name. */
  public static final String Z_KEYS_KEY = "Z_KEYS";
  /** Field name. */
  public static final String X_LABELS_KEY = "X_LABELS";
  /** Field name. */
  public static final String X_LABEL_TYPES_KEY = "X_LABEL_TYPES";
  /** Field name. */
  public static final String Y_LABELS_KEY = "Y_LABELS";
  /** Field name. */
  public static final String Y_LABEL_TYPES_KEY = "Y_LABEL_TYPES";
  /** Field name. */
  public static final String Z_LABELS_KEY = "Z_LABELS";
  /** Field name. */
  public static final String Z_LABEL_TYPES_KEY = "Z_LABEL_TYPES";
  /** Field name. */
  public static final String VALUES_KEY = "VALUES";

  private final Class<KX> _xKeyClass;
  private final Class<KY> _yKeyClass;
  private final Class<KZ> _zKeyClass;

  protected LabelledMatrix3DFudgeBuilder(final Class<KX> xKey, final Class<KY> yKey, final Class<KZ> zKey) {
    _xKeyClass = xKey;
    _yKeyClass = yKey;
    _zKeyClass = zKey;
  }

  protected Class<KX> getXKeyClass() {
    return _xKeyClass;
  }

  protected Class<KY> getYKeyClass() {
    return _yKeyClass;
  }

  protected Class<KZ> getZKeyClass() {
    return _zKeyClass;
  }

  @Override
  protected final void buildMessage(final FudgeSerializer serializer, final MutableFudgeMsg message, final T object) {
    s_logger.debug("Building message from {}", object);
    writeLabels(serializer, message, object.getXLabels(), X_LABELS_KEY, X_LABEL_TYPES_KEY);
    writeXKeys(serializer, message, object.getXKeys());
    writeLabels(serializer, message, object.getYLabels(), Y_LABELS_KEY, Y_LABEL_TYPES_KEY);
    writeYKeys(serializer, message, object.getYKeys());
    writeLabels(serializer, message, object.getZLabels(), Z_LABELS_KEY, Z_LABEL_TYPES_KEY);
    writeZKeys(serializer, message, object.getZKeys());
    writeValues(message, object.getValues());
    s_logger.debug("Built {}", message);
  }

  /**
   * General purpose label writer.
   *
   * @param serializer serialization context
   * @param message message to add the key to
   * @param labels labels to add
   * @param valueKey name of the field to hold label value information
   * @param typeKey name of the optional field to hold additional type information
   */
  protected void writeLabels(final FudgeSerializer serializer, final MutableFudgeMsg message, final Object[] labels, final String valueKey, final String typeKey) {
    final MutableFudgeMsg valueMsg = serializer.newMessage();
    final MutableFudgeMsg typeMsg = serializer.newMessage();
    boolean needsTypeInfo = false;
    for (Object label : labels) {
      final FudgeFieldType type = serializer.getFudgeContext().getTypeDictionary().getByJavaType(label.getClass());
      if (type == null) {
        serializer.addToMessage(valueMsg, null, null, label);
        valueMsg.add(null, null, FudgeWireType.SUB_MESSAGE, serializer.objectToFudgeMsg(label));
        typeMsg.add(null, null, label.getClass().getName());
        needsTypeInfo = true;
      } else {
        valueMsg.add(null, null, type, label);
        if (type instanceof SecondaryFieldType<?, ?>) {
          typeMsg.add(null, null, type.getJavaType().getName());
          needsTypeInfo = true;
        } else {
          typeMsg.add(null, null, type.getTypeId());
        }
      }
    }
    if (!needsTypeInfo) {
      // Message contains only primitive types; only put the type info in if there have been type reductions
      final Iterator<FudgeField> itrValueMsg = valueMsg.iterator();
      final Iterator<FudgeField> itrTypeMsg = typeMsg.iterator();
      while (itrValueMsg.hasNext()) {
        if (itrValueMsg.next().getType().getTypeId() != typeMsg.getFieldValue(Integer.class, itrTypeMsg.next())) {
          needsTypeInfo = true;
          break;
        }
      }
    }
    message.add(valueKey, valueMsg);
    if (needsTypeInfo) {
      message.add(typeKey, typeMsg);
    }
  }

  /**
   * General purpose key writer; defaults to {@link #writeKeys} - override in a subclass for more efficient handling.
   *
   * @param serializer serialization context
   * @param message message to add the key to
   * @param keys keys to add
   */
  protected void writeXKeys(final FudgeSerializer serializer, final MutableFudgeMsg message, final KX[] keys) {
    writeKeys(serializer, message, keys, getXKeyClass(), X_KEYS_KEY);
  }

  /**
   * General purpose key writer; defaults to {@link #writeKeys} - override in a subclass for more efficient handling.
   *
   * @param serializer serialization context
   * @param message message to add the key to
   * @param keys keys to add
   */
  protected void writeYKeys(final FudgeSerializer serializer, final MutableFudgeMsg message, final KY[] keys) {
    writeKeys(serializer, message, keys, getYKeyClass(), Y_KEYS_KEY);
  }

  /**
   * General purpose key writer; defaults to {@link #writeKeys} - override in a subclass for more efficient handling.
   *
   * @param serializer serialization context
   * @param message message to add the key to
   * @param keys keys to add
   */
  protected void writeZKeys(final FudgeSerializer serializer, final MutableFudgeMsg message, final KZ[] keys) {
    writeKeys(serializer, message, keys, getZKeyClass(), Z_KEYS_KEY);
  }

  /**
   * General purposes key writer; add each key as a field to a sub-message.
   *
   * @param <K> type of key
   * @param serializer serialization context
   * @param message message to add the keys to
   * @param keys keys to add
   * @param keyClass common base type of the keys (as known to the receiver)
   * @param keysKey name of the field to add the keys as
   */
  protected <K> void writeKeys(final FudgeSerializer serializer, final MutableFudgeMsg message, final K[] keys, final Class<K> keyClass, final String keysKey) {
    final MutableFudgeMsg submsg = serializer.newMessage();
    for (K key : keys) {
      serializer.addToMessageWithClassHeaders(submsg, null, null, key, keyClass);
    }
    message.add(keysKey, submsg);
  }

  protected void writeDoubleKeys(final MutableFudgeMsg message, final Double[] keys, final String keysKey) {
    final double[] arr = new double[keys.length];
    for (int i = 0; i < keys.length; i++) {
      arr[i] = keys[i];
    }
    message.add(keysKey, arr);
  }

  /**
   * General purpose value writer.
   *
   * @param message message to add the values to
   * @param values values to add
   */
  protected void writeValues(final MutableFudgeMsg message, final double[][][] values) {
    final int z = values.length;
    final int y = values[0].length;
    final int x = values[0][0].length;
    final double[] flat = new double[z * y * x];
    int i = 0;
    for (double[][] slice : values) {
      for (double[] row : slice) {
        System.arraycopy(row, 0, flat, i, row.length);
        i += row.length;
      }
    }
    message.add(VALUES_KEY, flat);
  }

  @Override
  public final T buildObject(final FudgeDeserializer deserializer, final FudgeMsg message) {
    s_logger.debug("Building object from {}", message);
    final KX[] xKeys = readXKeys(deserializer, message);
    final Object[] xLabels = readLabels(deserializer, message, X_LABELS_KEY, X_LABEL_TYPES_KEY);
    final KY[] yKeys = readYKeys(deserializer, message);
    final Object[] yLabels = readLabels(deserializer, message, Y_LABELS_KEY, Y_LABEL_TYPES_KEY);
    final KZ[] zKeys = readZKeys(deserializer, message);
    final Object[] zLabels = readLabels(deserializer, message, Z_LABELS_KEY, Z_LABEL_TYPES_KEY);
    final double[][][] values = readValues(message, xKeys.length, yKeys.length, zKeys.length);
    final T result = createMatrix(xKeys, xLabels, yKeys, yLabels, zKeys, zLabels, values);
    s_logger.debug("Built object {}", result);
    return result;
  }

  /**
   * Inverse of {@link #writeLabels}.
   *
   * @param deserializer deserialization context
   * @param message message to read from
   * @param labelsKey name of the field containing label values
   * @param labelTypesKey name of the optional field containing additional type information
   * @return new labels array
   */
  protected Object[] readLabels(final FudgeDeserializer deserializer, final FudgeMsg message, final String labelsKey, final String labelTypesKey) {
    final FudgeMsg valueMsg = message.getMessage(labelsKey);
    if (valueMsg == null) {
      s_logger.warn("Message field {} not found in {}", labelsKey, message);
      throw new IllegalArgumentException("Message is not a LabelledMatrix3D - does not contain a " + labelsKey + " field");
    }
    final Object[] labels = new Object[valueMsg.getNumFields()];
    final FudgeMsg typeMsg = message.getMessage(labelTypesKey);
    final Iterator<FudgeField> itrValue = valueMsg.iterator();
    final Iterator<FudgeField> itrType = (typeMsg != null) ? typeMsg.iterator() : null;
    int i = 0;
    while (itrValue.hasNext()) {
      Class<?> type = null;
      if (itrType != null) {
        final FudgeField typeField = itrType.next();
        final Object val = typeField.getValue();
        if (val instanceof String) {
          try {
            type = ClassUtils.loadClass((String) val);
          } catch (ClassNotFoundException e) {
            s_logger.warn("Message field {} requires unknown class {}", i, val);
            type = Object.class;
          }
        } else {
          type = deserializer.getFudgeContext().getTypeDictionary().getByTypeId(((Number) val).intValue()).getJavaType();
        }
      } else {
        type = Object.class;
      }
      labels[i++] = deserializer.fieldValueToObject(type, itrValue.next());
    }
    return labels;
  }

  /**
   * Inverse of {@link #readXKeys}.
   *
   * @param deserializer deserialization context
   * @param message message to read from
   * @return the keys
   */
  protected KX[] readXKeys(final FudgeDeserializer deserializer, final FudgeMsg message) {
    return readKeys(deserializer, message, getXKeyClass(), X_KEYS_KEY);
  }

  /**
   * Inverse of {@link #readXKeys}.
   *
   * @param deserializer deserialization context
   * @param message message to read from
   * @return the keys
   */
  protected KY[] readYKeys(final FudgeDeserializer deserializer, final FudgeMsg message) {
    return readKeys(deserializer, message, getYKeyClass(), Y_KEYS_KEY);
  }

  /**
   * Inverse of {@link #readXKeys}.
   *
   * @param deserializer deserialization context
   * @param message message to read from
   * @return the keys
   */
  protected KZ[] readZKeys(final FudgeDeserializer deserializer, final FudgeMsg message) {
    return readKeys(deserializer, message, getZKeyClass(), Z_KEYS_KEY);
  }

  /**
   * Inverse of {@link #writeKeys}.
   *
   * @param <K> key type
   * @param deserializer deserialization context
   * @param message message to read from
   * @param keyClass common base type of the keys (as understood by the sender)
   * @param keysKey name of the field containing the keys
   * @return the keys
   */
  @SuppressWarnings("unchecked")
  protected <K> K[] readKeys(final FudgeDeserializer deserializer, final FudgeMsg message, final Class<K> keyClass, final String keysKey) {
    final FudgeMsg submsg = message.getMessage(keysKey);
    if (submsg == null) {
      s_logger.warn("Message field {} not found in {}", keysKey, message);
      throw new IllegalArgumentException("Message is not a LabelledMatrix3D - does not contain a " + keysKey + " field");
    }
    final K[] keys = (K[]) Array.newInstance(keyClass, submsg.getNumFields());
    int i = 0;
    for (FudgeField key : submsg) {
      keys[i++] = deserializer.fieldValueToObject(keyClass, key);
    }
    return keys;
  }

  protected Double[] readDoubleKeys(final FudgeMsg message, final String keysKey) {
    final FudgeField field = message.getByName(keysKey);
    if (field == null) {
      s_logger.warn("Message field {} not found in {}", keysKey, message);
      throw new IllegalArgumentException("Message is not a LabelledMatrix3D - does not contain a " + keysKey + " field");
    }
    final double[] keys = message.getFieldValue(double[].class, field);
    final Double[] arr = new Double[keys.length];
    for (int i = 0; i < keys.length; i++) {
      arr[i] = keys[i];
    }
    return arr;
  }

  /**
   * Inverse of {@link #writeValues}.
   *
   * @param message message to read from
   * @param x number of values in the X dimension
   * @param y number of values in the Y dimension
   * @param z number of values in the Z dimension
   * @return the values
   */
  protected double[][][] readValues(final FudgeMsg message, final int x, final int y, final int z) {
    final FudgeField field = message.getByName(VALUES_KEY);
    if (field == null) {
      s_logger.warn("Message field {} not found in {}", VALUES_KEY, message);
      throw new IllegalArgumentException("Message is not a LabelledMatrix3D - does not contain a " + VALUES_KEY + " field");
    }
    final double[] flat = message.getFieldValue(double[].class, field);
    if (flat.length != x * y * z) {
      s_logger.warn("Invalid values length in {}", message);
      throw new IllegalArgumentException("Expected " + (x * y * z) + " matrix elements, got " + flat.length);
    }
    final double[][][] values = new double[z][y][x];
    int i = 0;
    for (double[][] slice : values) {
      for (double[] row : slice) {
        System.arraycopy(flat, i, row, 0, x);
        i += x;
      }
    }
    return values;
  }

  protected abstract T createMatrix(final KX[] xKeys, final Object[] xLabels, final KY[] yKeys, final Object[] yLabels, final KZ[] zKeys, final Object[] zLabels, final double[][][] values);

  /**
   * Builder for {@link DoubleLabelledMatrix3D}.
   */
  @FudgeBuilderFor(DoubleLabelledMatrix3D.class)
  public static final class DoubleBuilder extends LabelledMatrix3DFudgeBuilder<Double, Double, Double, DoubleLabelledMatrix3D> {

    public DoubleBuilder() {
      super(Double.class, Double.class, Double.class);
    }

    @Override
    protected void writeXKeys(final FudgeSerializer serializer, final MutableFudgeMsg message, final Double[] keys) {
      writeDoubleKeys(message, keys, X_KEYS_KEY);
    }

    @Override
    protected void writeYKeys(final FudgeSerializer serializer, final MutableFudgeMsg message, final Double[] keys) {
      writeDoubleKeys(message, keys, Y_KEYS_KEY);
    }

    @Override
    protected void writeZKeys(final FudgeSerializer serializer, final MutableFudgeMsg message, final Double[] keys) {
      writeDoubleKeys(message, keys, Z_KEYS_KEY);
    }

    @Override
    protected Double[] readXKeys(final FudgeDeserializer deserializer, final FudgeMsg message) {
      return readDoubleKeys(message, X_KEYS_KEY);
    }

    @Override
    protected Double[] readYKeys(final FudgeDeserializer deserializer, final FudgeMsg message) {
      return readDoubleKeys(message, Y_KEYS_KEY);
    }

    @Override
    protected Double[] readZKeys(final FudgeDeserializer deserializer, final FudgeMsg message) {
      return readDoubleKeys(message, Z_KEYS_KEY);
    }

    @Override
    protected DoubleLabelledMatrix3D createMatrix(final Double[] xKeys, final Object[] xLabels, final Double[] yKeys, final Object[] yLabels, final Double[] zKeys, final Object[] zLabels,
        final double[][][] values) {
      return new DoubleLabelledMatrix3D(xKeys, xLabels, yKeys, yLabels, zKeys, zLabels, values);
    }

  }

}
TOP

Related Classes of com.opengamma.financial.analytics.fudgemsg.LabelledMatrix3DFudgeBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.