Package com.opengamma.web.json

Source Code of com.opengamma.web.json.FudgeMsgJSONReader

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

import java.io.IOException;
import java.io.Reader;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.fudgemsg.FudgeContext;
import org.fudgemsg.FudgeFieldType;
import org.fudgemsg.FudgeMsg;
import org.fudgemsg.FudgeMsgEnvelope;
import org.fudgemsg.FudgeRuntimeException;
import org.fudgemsg.MutableFudgeMsg;
import org.fudgemsg.taxonomy.FudgeTaxonomy;
import org.fudgemsg.types.IndicatorType;
import org.fudgemsg.wire.FudgeRuntimeIOException;
import org.fudgemsg.wire.json.FudgeJSONSettings;
import org.fudgemsg.wire.types.FudgeWireType;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.threeten.bp.LocalDate;

import com.google.common.collect.Lists;
import com.opengamma.OpenGammaRuntimeException;

/**
* A Fudge reader that interprets JSON.
*/
public class FudgeMsgJSONReader {

  /**
   * The taxonomy identifier to use for any messages that are passed without envelopes.
   */
  private static final short DEFAULT_TAXONOMY_ID = 0;
  /**
   * The schema version to add to the envelope header for any messages that are passed without envelopes.
   */
  private static final int DEFAULT_MESSAGE_VERSION = 0;
  /**
   * The processing directive flags to add to the envelope header for any messages that are passed without envelopes.
   */
  private static final int DEFAULT_MESSAGE_PROCESSING_DIRECTIVES = 0;

  private final FudgeJSONSettings _settings;
  private final FudgeContext _fudgeContext;
  private final Reader _underlying;
  private int _taxonomyId = DEFAULT_TAXONOMY_ID;
  private FudgeTaxonomy _taxonomy;
  private int _processingDirectives = DEFAULT_MESSAGE_PROCESSING_DIRECTIVES;
  private int _schemaVersion = DEFAULT_MESSAGE_VERSION;
  private JSONObject _jsonObject;
  private final List<String> _envelopeAttibutesFields = Lists.newArrayList();

  /**
   * Creates a new instance for reading a Fudge stream from a JSON reader.
   *
   * @param fudgeContext  the Fudge context, not null
   * @param reader  the underlying reader, not null
   */
  public FudgeMsgJSONReader(final FudgeContext fudgeContext, final Reader reader) {
    this(fudgeContext, reader, new FudgeJSONSettings());
  }

  /**
   * Creates a new instance for reading a Fudge stream from a JSON reader.
   *
   * @param fudgeContext  the Fudge context, not null
   * @param reader  the underlying reader, not null
   * @param settings  the JSON settings to fine tune the read, not null
   */
  public FudgeMsgJSONReader(final FudgeContext fudgeContext, final Reader reader, final FudgeJSONSettings settings) {
    _fudgeContext = fudgeContext;
    _underlying = reader;
    _settings = settings;
    try {
      _jsonObject = new JSONObject(new JSONTokener(reader));
      init(_fudgeContext, _jsonObject, _settings);
    } catch (final JSONException ex) {
      wrapException("Creating json object from reader", ex);
    }
  }

  private void init(final FudgeContext fudgeContext, final JSONObject jsonObject, final FudgeJSONSettings settings) throws JSONException {
    final String processingDirectivesField = settings.getProcessingDirectivesField();
    if (jsonObject.has(processingDirectivesField)) {
      _processingDirectives = integerValue(jsonObject.get(processingDirectivesField));
      _envelopeAttibutesFields.add(processingDirectivesField);
    }
    final String schemaVersionField = getSettings().getSchemaVersionField();
    if (jsonObject.has(schemaVersionField)) {
      _schemaVersion = integerValue(jsonObject.get(schemaVersionField));
      _envelopeAttibutesFields.add(schemaVersionField);
    }
    final String taxonomyField = getSettings().getTaxonomyField();
    if (jsonObject.has(taxonomyField)) {
      _taxonomyId = integerValue(jsonObject.get(taxonomyField));
      _taxonomy = fudgeContext.getTaxonomyResolver().resolveTaxonomy((short) _taxonomyId);
      _envelopeAttibutesFields.add(taxonomyField);
    }
  }

  //-------------------------------------------------------------------------
  /**
   * Gets the underlying reader.
   *
   * @return the reader, not null
   */
  public Reader getUnderlying() {
    return _underlying;
  }

  /**
   * Gets the fudgeContext.
   * @return the fudgeContext
   */
  public FudgeContext getFudgeContext() {
    return _fudgeContext;
  }

  /**
   * Gets the settings.
   * @return the settings
   */
  public FudgeJSONSettings getSettings() {
    return _settings;
  }

  private RuntimeException wrapException(String message, final JSONException ex) {
    message = "Error " + message + " from JSON stream";
    if (ex.getCause() instanceof IOException) {
      return new FudgeRuntimeIOException(message, (IOException) ex.getCause());
    } else {
      return new FudgeRuntimeException(message, ex);
    }
  }


  /**
   * Reads the next message, discarding the envelope.
   *
   * @return the message read without the envelope
   */
  public FudgeMsg readMessage() {
    final FudgeMsgEnvelope msgEnv = readMessageEnvelope();
    if (msgEnv == null) {
      return null;
    }
    return msgEnv.getMessage();
  }


  /**
   * Reads the next message, returning the envelope.
   *
   * @return the {@link FudgeMsgEnvelope}
   */
  public FudgeMsgEnvelope readMessageEnvelope() {
    FudgeMsgEnvelope msgEnv = null;
    try {
      final JSONObject meta = (JSONObject) _jsonObject.get("meta");
      final JSONObject data = (JSONObject) _jsonObject.get("data");
      final MutableFudgeMsg msg = processFields(data, meta);
      msgEnv = getFudgeMsgEnvelope(msg, _jsonObject);
    } catch (final JSONException ex) {
      wrapException("reading message envelope", ex);
    }
    return msgEnv;
  }

  private FudgeMsgEnvelope getFudgeMsgEnvelope(final MutableFudgeMsg fudgeMsg, final JSONObject jsonObject) throws JSONException {
    return new FudgeMsgEnvelope(fudgeMsg, _schemaVersion, _processingDirectives);
  }

  private int integerValue(final Object o) {
    if (o instanceof Number) {
      return ((Number) o).intValue();
    } else if (o instanceof String) {
      return Integer.parseInt((String) o);
    } else {
      throw new NumberFormatException(o + " is not a number");
    }
  }

  private byte byteValue(final Object o) {
    if (o instanceof Number) {
      return ((Number) o).byteValue();
    } else if (o instanceof String) {
      return Byte.parseByte((String) o);
    } else {
      throw new NumberFormatException(o + " is not a number");
    }
  }

  private short shortValue(final Object o) {
    if (o instanceof Number) {
      return ((Number) o).shortValue();
    } else if (o instanceof String) {
      return Short.parseShort((String) o);
    } else {
      throw new NumberFormatException(o + " is not a number");
    }
  }

  private long longValue(final Object o) {
    if (o instanceof Number) {
      return ((Number) o).longValue();
    } else if (o instanceof String) {
      return Long.parseLong((String) o);
    } else {
      throw new NumberFormatException(o + " is not a number");
    }
  }

  private double doubleValue(final Object o) {
    if (o instanceof Number) {
      return ((Number) o).doubleValue();
    } else if (o instanceof String) {
      return Double.parseDouble((String) o);
    } else {
      throw new NumberFormatException(o + " is not a number");
    }
  }

  private float floatValue(final Object o) {
    if (o instanceof Number) {
      return ((Number) o).floatValue();
    } else if (o instanceof String) {
      return Float.parseFloat((String) o);
    } else {
      throw new NumberFormatException(o + " is not a number");
    }
  }

  private MutableFudgeMsg processFields(final JSONObject data, final JSONObject meta) {
    final MutableFudgeMsg fudgeMsg = getFudgeContext().newMessage();
    @SuppressWarnings("unchecked")
    final
    Iterator<String> keys = data.keys();
    while (keys.hasNext()) {
      final String fieldName = keys.next();
      final Object dataValue = getFieldValue(data, fieldName);
      final Object metaValue = getFieldValue(meta, fieldName);
      if (dataValue instanceof JSONObject) {
        final MutableFudgeMsg subMsg = processFields((JSONObject) dataValue, (JSONObject) metaValue);
        addField(fudgeMsg, fieldName, FudgeWireType.SUB_MESSAGE, subMsg);
      } else if (dataValue instanceof JSONArray) {
        final JSONArray dataArray = (JSONArray) dataValue;
        if (dataArray.length() > 0) {
          if (isPrimitiveArray(metaValue)) {
            try {
              final FudgeFieldType fieldType = getFieldType((String) metaValue);
              if (fieldType == null) {
                throw new OpenGammaRuntimeException("Unknown field type " + metaValue + " for " + fieldName + ":" + dataValue);
              }
              final Object primitiveArray = jsonArrayToPrimitiveArray(dataArray, fieldType);
              addField(fudgeMsg, fieldName, getFieldType((String) metaValue), primitiveArray);
            } catch (final JSONException e) {
              wrapException("converting json array to primitive array", e);
            }
          } else {
            //treat as repeated fields
            addRepeatedFields(fudgeMsg, fieldName, dataArray, (JSONArray) metaValue);
          }
        }
      } else {
        final FudgeFieldType fieldType = getFieldType((String) metaValue);
        if (fieldType == null) {
          throw new OpenGammaRuntimeException("Unknown field type " + metaValue + " for " + fieldName + ":" + dataValue);
        }
        addField(fudgeMsg, fieldName, fieldType, dataValue);
      }
    }
    return fudgeMsg;
  }

  private boolean isPrimitiveArray(final Object metaValue) {
    if (metaValue instanceof JSONArray) {
      return false;
    }
    return true;
  }

  private void addField(final MutableFudgeMsg fudgeMsg, final String fieldName, final FudgeFieldType fieldType, final Object fieldValue) {
    Integer ordinal = null;
    String name = null;
    try {
      ordinal = Integer.parseInt(fieldName);
    } catch (final NumberFormatException nfe) {
      if (StringUtils.isNotEmpty(fieldName)) {
        if (!getPreserveFieldNames()) {
          if (_taxonomy != null) {
            ordinal = _taxonomy.getFieldOrdinal(fieldName);
          }
        } else {
          name = fieldName;
        }
      }
    }
    switch (fieldType.getTypeId()) {
      case FudgeWireType.BYTE_TYPE_ID:
        fudgeMsg.add(name, ordinal, fieldType, byteValue(fieldValue));
        break;
      case FudgeWireType.SHORT_TYPE_ID:
        fudgeMsg.add(name, ordinal, fieldType, shortValue(fieldValue));
        break;
      case FudgeWireType.DOUBLE_TYPE_ID:
        fudgeMsg.add(name, ordinal, fieldType, doubleValue(fieldValue));
        break;
      case FudgeWireType.FLOAT_TYPE_ID:
        fudgeMsg.add(name, ordinal, fieldType, floatValue(fieldValue));
        break;
      case FudgeWireType.DATE_TYPE_ID:
        fudgeMsg.add(name, ordinal, fieldType, toLocalDate(fieldValue));
        break;
      case FudgeWireType.LONG_TYPE_ID:
        fudgeMsg.add(name, ordinal, fieldType, longValue(fieldValue));
        break;
      default:
        fudgeMsg.add(name, ordinal, fieldType, fieldValue);
        break;
    }
  }

  private LocalDate toLocalDate(final Object fieldValue) {
    if (fieldValue != null) {
      return LocalDate.parse((String) fieldValue);
    }
    return null;
  }

  private boolean getPreserveFieldNames() {
    return getSettings().getPreserveFieldNames();
  }

  private void addRepeatedFields(final MutableFudgeMsg fudgeMsg, final String fieldName, final JSONArray dataArray, final JSONArray metaArray) {
    try {
      for (int i = 0; i < dataArray.length(); i++) {
        final Object arrValue = dataArray.get(i);
        final Object metaValue = metaArray.get(i);
        if (arrValue instanceof JSONObject) {
          final MutableFudgeMsg subMsg = processFields((JSONObject) arrValue, (JSONObject) metaValue);
          addField(fudgeMsg, fieldName, FudgeWireType.SUB_MESSAGE, subMsg);
        } else {
          final FudgeFieldType fieldType = getFieldType((String) metaValue);
          if (fieldType == null) {
            throw new OpenGammaRuntimeException("Unknown field type " + metaValue + " for " + fieldName + ":" + arrValue);
          }
          addField(fudgeMsg, fieldName, fieldType, arrValue);
        }
      }
    } catch (final JSONException e) {
      wrapException("adding repeated fields", e);
    }
  }

  private FudgeFieldType getFieldType(final String typeValue) {
    final Integer typeId = getSettings().stringToFudgeTypeId(typeValue);
    return getFudgeContext().getTypeDictionary().getByTypeId(typeId);
  }

  private Object jsonArrayToPrimitiveArray(final JSONArray arr, final FudgeFieldType fieldType) throws JSONException {
    switch (fieldType.getTypeId()) {
      case FudgeWireType.BYTE_ARRAY_TYPE_ID:
      case FudgeWireType.BYTE_ARRAY_4_TYPE_ID:
      case FudgeWireType.BYTE_ARRAY_8_TYPE_ID:
      case FudgeWireType.BYTE_ARRAY_16_TYPE_ID:
      case FudgeWireType.BYTE_ARRAY_20_TYPE_ID:
      case FudgeWireType.BYTE_ARRAY_32_TYPE_ID:
      case FudgeWireType.BYTE_ARRAY_64_TYPE_ID:
      case FudgeWireType.BYTE_ARRAY_128_TYPE_ID:
      case FudgeWireType.BYTE_ARRAY_256_TYPE_ID:
      case FudgeWireType.BYTE_ARRAY_512_TYPE_ID:
        final byte[] byteArr = new byte[arr.length()];
        for (int j = 0; j < byteArr.length; j++) {
          byteArr[j] = ((Number) arr.get(j)).byteValue();
        }
        return byteArr;
      case FudgeWireType.SHORT_ARRAY_TYPE_ID:
        final short[] shortArr = new short[arr.length()];
        for (int j = 0; j < shortArr.length; j++) {
          shortArr[j] = ((Number) arr.get(j)).shortValue();
        }
        return shortArr;
      case FudgeWireType.INT_ARRAY_TYPE_ID:
        final int[] intArr = new int[arr.length()];
        for (int j = 0; j < intArr.length; j++) {
          intArr[j] = ((Number) arr.get(j)).intValue();
        }
        return intArr;
      case FudgeWireType.LONG_ARRAY_TYPE_ID:
        final long[] longArr = new long[arr.length()];
        for (int j = 0; j < longArr.length; j++) {
          longArr[j] = ((Number) arr.get(j)).longValue();
        }
        return longArr;
      case FudgeWireType.DOUBLE_ARRAY_TYPE_ID:
        final double[] doubleArr = new double[arr.length()];
        for (int j = 0; j < doubleArr.length; j++) {
          doubleArr[j] = ((Number) arr.get(j)).doubleValue();
        }
        return doubleArr;
      case FudgeWireType.FLOAT_ARRAY_TYPE_ID:
        final float[] floatArr = new float[arr.length()];
        for (int j = 0; j < floatArr.length; j++) {
          floatArr[j] = ((Number) arr.get(j)).floatValue();
        }
        return floatArr;
      default:
        return null;
    }
  }

  private Object getFieldValue(final JSONObject jsonObject, final String fieldName) {
    Object fieldValue = null;
    try {
      fieldValue = jsonObject.get(fieldName);
      if (JSONObject.NULL.equals(fieldValue)) {
        fieldValue = IndicatorType.INSTANCE;
      }
    } catch (final JSONException e) {
      wrapException("reading field value", e);
    }
    return fieldValue;
  }

}
TOP

Related Classes of com.opengamma.web.json.FudgeMsgJSONReader

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.