sgammon/GUST

View on GitHub
java/gust/backend/model/CollapsedMessageCodec.java

Summary

Maintainability
A
0 mins
Test Coverage
/*
 * Copyright © 2020, The Gust Framework Authors. All rights reserved.
 *
 * The Gust/Elide framework and tools, and all associated source or object computer code, except where otherwise noted,
 * are licensed under the Zero Prosperity license, which is enclosed in this repository, in the file LICENSE.txt. Use of
 * this code in object or source form requires and implies consent and agreement to that license in principle and
 * practice. Source or object code not listing this header, or unless specified otherwise, remain the property of
 * Elide LLC and its suppliers, if any. The intellectual and technical concepts contained herein are proprietary to
 * Elide LLC and its suppliers and may be covered by U.S. and Foreign Patents, or patents in process, and are protected
 * by trade secret and copyright law. Dissemination of this information, or reproduction of this material, in any form,
 * is strictly forbidden except in adherence with assigned license requirements.
 */
package gust.backend.model;

import com.google.protobuf.Message;
import io.micronaut.context.annotation.Context;
import io.micronaut.context.annotation.Factory;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;


/**
 *
 *
 * @param <Model>
 * @param <ReadIntermediate>
 */
@Factory
@Immutable
@ThreadSafe
public final class CollapsedMessageCodec<Model extends Message, ReadIntermediate>
    implements ModelCodec<Model, CollapsedMessage, ReadIntermediate> {
  /** Builder proto-type used to spawn new instances. */
  private final Message.Builder builder;

  /** Default model instance to build with. */
  private final Model instance;

  /** Singleton access to serializer. */
  private final CollapsedMessageSerializer serializer = new CollapsedMessageSerializer();

  /** Deserializer for the model, provided at construction time. */
  private final ModelDeserializer<ReadIntermediate, Model> deserializer;

  private CollapsedMessageCodec(@Nonnull Model instance,
                                @Nonnull ModelDeserializer<ReadIntermediate, Model> deserializer) {
    this.instance = instance;
    this.builder = instance.newBuilderForType();
    this.deserializer = deserializer;
  }

  /**
   * Create a collapsed message codec which adapts the provided builder to {@link CollapsedMessage} and back. These
   * "collapsed" messages follow the framework-defined protocol for serializing hierarchical data.
   *
   * @param <M> Model type for which we will construct or otherwise resolve a collapsed message codec.
   * @return Collapsed message codec bound to the provided message type.
   */
  @Context
  public static @Nonnull <M extends Message, RI> CollapsedMessageCodec<M, RI> forModel(
      M instance, ModelDeserializer<RI, M> deserializer) {
    return new CollapsedMessageCodec<>(instance, deserializer);
  }

  /**
   * Acquire an instance of the {@link ModelSerializer} attached to this adapter. The instance is not guaranteed to be
   * created fresh for this invocation.
   *
   * @return Serializer instance.
   * @see #deserializer() For the inverse of this method.
   * @see #deserialize(Object) To call into de-serialization directly.
   */
  @Override
  public @Nonnull ModelSerializer<Model, CollapsedMessage> serializer() {
    return serializer;
  }

  /**
   * Acquire an instance of the {@link ModelDeserializer} attached to this adapter. The instance is not guaranteed to be
   * created fresh for this invocation.
   *
   * @return Deserializer instance.
   * @see #serializer() For the inverse of this method.
   * @see #serialize(Message) To call into serialization directly.
   */
  @Override
  public @Nonnull ModelDeserializer<ReadIntermediate, Model> deserializer() {
    return deserializer;
  }

  /** Serializes model instances into {@link CollapsedMessage} objects. */
  private final class CollapsedMessageSerializer implements ModelSerializer<Model, CollapsedMessage> {
    /**
     * Serialize a model instance from the provided object type to the specified output type, throwing exceptions
     * verbosely if we are unable to correctly and properly export the record.
     *
     * @param input Input record object to serialize.
     * @return Serialized record data, of the specified output type.
     * @throws ModelDeflateException If the model fails to export or serialize for any reason.
     */
    @Override
    public @Nonnull CollapsedMessage deflate(@Nonnull Message input) throws ModelDeflateException {
      return ObjectModelSerializer.Companion
          .defaultInstance()
          .collapse(input, null, null, WriteDisposition.BLIND);
    }
  }

  /** @return Builder for the model handled by this codec. */
  public Message.Builder getBuilder() {
    return builder;
  }

  /** @return Default model instance. */
  @Override
  public @Nonnull Model instance() {
    return this.instance;
  }
}