Artifact Content
Not logged in

Artifact 5ea2e633b62f72b11958c7a72fda467862655361:


package org.interledger.codecs.oer.ilp;

import org.interledger.InterledgerAddress;
import org.interledger.codecs.Codec;
import org.interledger.codecs.CodecContext;
import org.interledger.codecs.InterledgerProtocolErrorCodec;
import org.interledger.codecs.oer.OerGeneralizedTimeCodec.OerGeneralizedTime;
import org.interledger.codecs.oer.OerIA5StringCodec.OerIA5String;
import org.interledger.codecs.oer.OerOctetStringCodec.OerOctetString;
import org.interledger.codecs.oer.OerSequenceOfAddressCodec.OerSequenceOfAddress;
import org.interledger.codecs.packettypes.InterledgerPacketType;
import org.interledger.ilp.InterledgerProtocolError;
import org.interledger.ilp.InterledgerProtocolError.ErrorCode;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.Instant;
import java.util.List;
import java.util.Objects;

/**
 * <p>An implementation of {@link Codec} that reads and writes instances of {@link
 * InterledgerProtocolError}.</p>
 *
 * <p>The ASN.1 OER definition of an InterledgerProtocolError defines it as an extensible sequence.
 * Thus, this sequence must have the following: </p>
 *
 * <p><b>Presence Bitmap</b> The presence bitmap is encoded as a "bit string" with a fixed size
 * constraint, and has one bit for each field of the sequence type that has the keyword OPTIONAL or
 * DEFAULT, in specification order. Because the InterledgerProtocolError has no optional/default
 * values, there is no presence bitmap. As an example of this, reference "Overview of OER Encoding",
 * example B, which also has no presence bitmap since no fields are optional/default.</p>
 *
 * <p><b>Extension Presence Bitmap</b> This implementation does not currently support extensions,
 * and therefore does not encode nor decode an "extension presence bitmap". If it did, in order to
 * indicate an extension, the presence bitmap must be present, and the MSB of the bitmap must be 1,
 * and further rules. Reference section 2.8 "Encoding of a Sequence Type" in "Overview of OER" for
 * more details. </p>
 *
 * <p><b>Components</b> The rest of the packet is the concatenation of the encodings of the fields
 * of the sequence type that are present in the value, in specification order. </p>
 *
 * @see "http://www.oss.com/asn1/resources/books-whitepapers-pubs/Overview%20of%20OER.pdf"
 */
public class InterledgerProtocolProtocolErrorOerCodec implements InterledgerProtocolErrorCodec {

  @Override
  public InterledgerProtocolError read(final CodecContext context, final InputStream inputStream)
      throws IOException {
    Objects.requireNonNull(context);
    Objects.requireNonNull(inputStream);

    // 1. InterledgerProtocolError has no "presence bitmap". See javadoc for this class for more
    // details.

    // 2. InterledgerProtocolError has no "extension presence bitmap". See javadoc for this class
    // for more details.

    // 3. Read the code, which is an IA5String.
    final String code = context.read(OerIA5String.class, inputStream).getValue();

    // 4. Read the name, which is a IA5String.
    final String name = context.read(OerIA5String.class, inputStream).getValue();

    final ErrorCode errorCode = ErrorCode.of(code, name);

    // 5. Read the triggeredBy address, which is an InterledgerAddress
    final InterledgerAddress triggeredByAddress =
        context.read(InterledgerAddress.class, inputStream);

    // 6. Read the forwardedBy,which is a SEQUENCE OF InterledgerAddress
    final List<InterledgerAddress> addressList =
        context.read(OerSequenceOfAddress.class, inputStream).getInterledgerAddresses();

    // 7. Read the triggeredAt, which is a Timestamp
    final Instant triggeredAt = context.read(OerGeneralizedTime.class, inputStream).getValue();

    // 8. Read the data, which is an OctetString.
    final byte[] data = context.read(OerOctetString.class, inputStream)
        .getValue();

    return InterledgerProtocolError.builder()
        .errorCode(errorCode)
        .triggeredByAddress(triggeredByAddress)
        .forwardedByAddresses(addressList)
        .triggeredAt(triggeredAt)
        .data(data)
        .build();
  }

  @Override
  public void write(final CodecContext context, final InterledgerProtocolError instance,
      final OutputStream outputStream) throws IOException {
    Objects.requireNonNull(context);
    Objects.requireNonNull(instance);
    Objects.requireNonNull(outputStream);

    // 1. InterledgerProtocolError has no "presence bitmap". See javadoc for this class for more
    // details.

    // 2. InterledgerProtocolError has no "extension presence bitmap". See javadoc for this class
    // for more details.

    // 3. Write the packet type.
    context.write(InterledgerPacketType.class, this.getTypeId(), outputStream);

    // 4. Write the Error code, which is an IA5String.
    context.write(new OerIA5String(instance.getErrorCode().getCode()), outputStream);

    // 5. Write the Error name, which is a IA5String.
    context.write(new OerIA5String(instance.getErrorCode().getName()), outputStream);

    // 5. Write the triggeredBy address, which is an InterledgerAddress
    context.write(instance.getTriggeredByAddress(), outputStream);

    // 6. Write the forwardedBy addresses, which is a SEQUENCE OF InterledgerAddress
    context.write(new OerSequenceOfAddress(instance.getForwardedByAddresses()), outputStream);

    // 7. Write the triggeredAt, which is a Timestamp
    context.write(new OerGeneralizedTime(instance.getTriggeredAt()), outputStream);

    // 8. Write the data, which is an OctetString.
    instance.getData().ifPresent(data -> {
      try {
        context.write(OerOctetString.class, new OerOctetString(data), outputStream);
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    });
  }
}