All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.sayayi.lib.message.pack.PackHelper Maven / Gradle / Ivy

Go to download

Highly configurable message format library supporting message definition through annotations

The newest version!
/*
 * Copyright 2023 Jeroen Gremmen
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.sayayi.lib.message.pack;

import de.sayayi.lib.message.Message;
import de.sayayi.lib.message.internal.*;
import de.sayayi.lib.message.part.MessagePart;
import de.sayayi.lib.message.part.NoSpaceTextPart;
import de.sayayi.lib.message.part.TemplatePart;
import de.sayayi.lib.message.part.TextPart;
import de.sayayi.lib.message.part.parameter.ParameterPart;
import de.sayayi.lib.message.part.parameter.key.*;
import de.sayayi.lib.message.part.parameter.value.*;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static java.util.function.Function.identity;


/**
 * This class provides methods for packing and unpacking message (and related) objects.
 *
 * @author Jeroen Gremmen
 * @since 0.8.0
 */
public final class PackHelper
{
  private static final int MAP_KEY_BOOL_ID = 0;
  private static final int MAP_KEY_EMPTY_ID = 1;
  private static final int MAP_KEY_NAME_ID = 2;
  private static final int MAP_KEY_NULL_ID = 3;
  private static final int MAP_KEY_NUMBER_ID = 4;
  private static final int MAP_KEY_STRING_ID = 5;
  private static final int MAP_KEY_DEFAULT_ID = 6;

  private static final int MAP_VALUE_BOOL_ID = 0;
  private static final int MAP_VALUE_MESSAGE_ID = 1;
  private static final int MAP_VALUE_NUMBER_ID = 2;
  private static final int MAP_VALUE_STRING_ID = 3;

  private static final int PART_NO_SPACE_TEXT_ID = 0;
  private static final int PART_PARAMETER_ID = 1;
  private static final int PART_TEXT_ID = 2;
  private static final int PART_TEMPLATE_ID = 3;

  private static final int MESSAGE_EMPTY = 0;
  private static final int MESSAGE_EMPTY_WITH_CODE = 1;
  private static final int MESSAGE_LOCALIZED_BUNDLE_WITH_CODE = 2;
  private static final int MESSAGE_DELEGATE_WITH_CODE = 3;
  private static final int MESSAGE_COMPOUND = 4;
  private static final int MESSAGE_TEXT = 5;


  private final Map mapKeys = new HashMap<>();
  private final Map mapValues = new HashMap<>();
  private final Map messageParts = new HashMap<>();
  private final Map messagesWithSpaces = new HashMap<>();


  public static void pack(@NotNull Message message, @NotNull PackOutputStream packStream)
      throws IOException
  {
    if (message instanceof EmptyMessage)
      packStream.writeSmall(MESSAGE_EMPTY, 3);
    else if (message instanceof EmptyMessageWithCode)
    {
      packStream.writeSmall(MESSAGE_EMPTY_WITH_CODE, 3);
      ((EmptyMessageWithCode)message).pack(packStream);
    }
    else if (message instanceof LocalizedMessageBundleWithCode)
    {
      packStream.writeSmall(MESSAGE_LOCALIZED_BUNDLE_WITH_CODE, 3);
      ((LocalizedMessageBundleWithCode)message).pack(packStream);
    }
    else if (message instanceof MessageDelegateWithCode)
    {
      packStream.writeSmall(MESSAGE_DELEGATE_WITH_CODE, 3);
      ((MessageDelegateWithCode)message).pack(packStream);
    }
    else if (message instanceof CompoundMessage)
    {
      packStream.writeSmall(MESSAGE_COMPOUND, 3);
      ((CompoundMessage)message).pack(packStream);
    }
    else if (message instanceof TextMessage)
    {
      packStream.writeSmall(MESSAGE_TEXT, 3);
      ((TextMessage)message).pack(packStream);
    }
    else
    {
      throw new IllegalArgumentException("unknown message type " +
          message.getClass().getSimpleName());
    }
  }


  public @NotNull Message.WithSpaces unpackMessageWithSpaces(@NotNull PackInputStream packStream)
      throws IOException
  {
    final Message.WithSpaces message;

    switch(packStream.readSmall(3))
    {
      case MESSAGE_EMPTY:
        return EmptyMessage.INSTANCE;

      case MESSAGE_COMPOUND:
        message = CompoundMessage.unpack(this, packStream);
        break;

      case MESSAGE_TEXT:
        message = TextMessage.unpack(packStream);
        break;

      default:
        throw new IllegalStateException("message with spaces expected");
    }

    return messagesWithSpaces.computeIfAbsent(message, identity());
  }


  public @NotNull Message.WithCode unpackMessageWithCode(@NotNull PackInputStream packStream)
      throws IOException
  {
    switch(packStream.readSmall(3))
    {
      case MESSAGE_EMPTY_WITH_CODE:
        return EmptyMessageWithCode.unpack(packStream);

      case MESSAGE_LOCALIZED_BUNDLE_WITH_CODE:
        return LocalizedMessageBundleWithCode.unpack(this, packStream);

      case MESSAGE_DELEGATE_WITH_CODE:
        return MessageDelegateWithCode.unpack(this, packStream);
    }

    throw new IllegalStateException("message with code expected");
  }


  public @NotNull Message unpackMessage(@NotNull PackInputStream packStream) throws IOException
  {
    final Message.WithSpaces message;

    switch(packStream.readSmall(3))
    {
      case MESSAGE_EMPTY:
        return EmptyMessage.INSTANCE;

      case MESSAGE_EMPTY_WITH_CODE:
        return EmptyMessageWithCode.unpack(packStream);

      case MESSAGE_LOCALIZED_BUNDLE_WITH_CODE:
        return LocalizedMessageBundleWithCode.unpack(this, packStream);

      case MESSAGE_DELEGATE_WITH_CODE:
        return MessageDelegateWithCode.unpack(this, packStream);

      case MESSAGE_COMPOUND:
        message = CompoundMessage.unpack(this, packStream);
        break;

      case MESSAGE_TEXT:
        message = TextMessage.unpack(packStream);
        break;

      default:
        throw new IllegalStateException("message expected");
    }

    return messagesWithSpaces.computeIfAbsent(message, identity());
  }


  public static void pack(@NotNull MessagePart messagePart, @NotNull PackOutputStream packStream)
      throws IOException
  {
    if (messagePart instanceof ParameterPart)
    {
      packStream.writeSmall(PART_PARAMETER_ID, 2);
      ((ParameterPart)messagePart).pack(packStream);
    }
    else if (messagePart instanceof NoSpaceTextPart)
    {
      packStream.writeSmall(PART_NO_SPACE_TEXT_ID, 2);
      ((NoSpaceTextPart)messagePart).pack(packStream);
    }
    else if (messagePart instanceof TextPart)
    {
      packStream.writeSmall(PART_TEXT_ID, 2);
      ((TextPart)messagePart).pack(packStream);
    }
    else if (messagePart instanceof TemplatePart)
    {
      packStream.writeSmall(PART_TEMPLATE_ID, 2);
      ((TemplatePart)messagePart).pack(packStream);
    }
    else
    {
      throw new IllegalArgumentException("unknown message part type " +
          messagePart.getClass().getSimpleName());
    }
  }


  public @NotNull MessagePart unpackMessagePart(@NotNull PackInputStream packStream)
      throws IOException
  {
    final MessagePart messagePart;

    switch(packStream.readSmall(2))
    {
      case PART_NO_SPACE_TEXT_ID:
        messagePart = NoSpaceTextPart.unpack(packStream);
        break;

      case PART_PARAMETER_ID:
        messagePart = ParameterPart.unpack(this, packStream);
        break;

      case PART_TEXT_ID:
        messagePart = TextPart.unpack(packStream);
        break;

      case PART_TEMPLATE_ID:
        messagePart = TemplatePart.unpack(this, packStream);
        break;

      default:
        throw new IllegalStateException("message part expected");
    }

    return messageParts.computeIfAbsent(messagePart, identity());
  }


  public static void pack(ConfigKey configKey, @NotNull PackOutputStream packStream)
      throws IOException
  {
    if (configKey == null)
      packStream.writeSmall(MAP_KEY_DEFAULT_ID, 3);
    else if (configKey instanceof ConfigKeyBool)
    {
      packStream.writeSmall(MAP_KEY_BOOL_ID, 3);
      ((ConfigKeyBool)configKey).pack(packStream);
    }
    else if (configKey instanceof ConfigKeyEmpty)
    {
      packStream.writeSmall(MAP_KEY_EMPTY_ID, 3);
      ((ConfigKeyEmpty)configKey).pack(packStream);
    }
    else if (configKey instanceof ConfigKeyName)
    {
      packStream.writeSmall(MAP_KEY_NAME_ID, 3);
      ((ConfigKeyName)configKey).pack(packStream);
    }
    else if (configKey instanceof ConfigKeyNull)
    {
      packStream.writeSmall(MAP_KEY_NULL_ID, 3);
      ((ConfigKeyNull)configKey).pack(packStream);
    }
    else if (configKey instanceof ConfigKeyNumber)
    {
      packStream.writeSmall(MAP_KEY_NUMBER_ID, 3);
      ((ConfigKeyNumber)configKey).pack(packStream);
    }
    else if (configKey instanceof ConfigKeyString)
    {
      packStream.writeSmall(MAP_KEY_STRING_ID, 3);
      ((ConfigKeyString)configKey).pack(packStream);
    }
    else
    {
      throw new IllegalArgumentException("unknown map key type " +
          configKey.getClass().getSimpleName());
    }
  }


  public ConfigKey unpackMapKey(@NotNull PackInputStream packStream) throws IOException
  {
    final ConfigKey configKey;

    switch(packStream.readSmall(3))
    {
      case MAP_KEY_BOOL_ID:
        configKey = ConfigKeyBool.unpack(packStream);
        break;

      case MAP_KEY_EMPTY_ID:
        configKey = ConfigKeyEmpty.unpack(packStream);
        break;

      case MAP_KEY_NAME_ID:
        configKey = ConfigKeyName.unpack(packStream);
        break;

      case MAP_KEY_NULL_ID:
        configKey = ConfigKeyNull.unpack(packStream);
        break;

      case MAP_KEY_NUMBER_ID:
        configKey = ConfigKeyNumber.unpack(packStream);
        break;

      case MAP_KEY_STRING_ID:
        configKey = ConfigKeyString.unpack(packStream);
        break;

      case MAP_KEY_DEFAULT_ID:
        configKey = null;
        break;

      default:
        throw new IllegalStateException("map key expected");
    }

    return mapKeys.computeIfAbsent(configKey, identity());
  }


  public static void pack(@NotNull ConfigValue configValue, @NotNull PackOutputStream packStream)
      throws IOException
  {
    if (configValue instanceof ConfigValueBool)
    {
      packStream.writeSmall(MAP_VALUE_BOOL_ID, 2);
      ((ConfigValueBool)configValue).pack(packStream);
    }
    else if (configValue instanceof ConfigValueMessage)
    {
      packStream.writeSmall(MAP_VALUE_MESSAGE_ID, 2);
      ((ConfigValueMessage)configValue).pack(packStream);
    }
    else if (configValue instanceof ConfigValueNumber)
    {
      packStream.writeSmall(MAP_VALUE_NUMBER_ID, 2);
      ((ConfigValueNumber)configValue).pack(packStream);
    }
    else if (configValue instanceof ConfigValueString)
    {
      packStream.writeSmall(MAP_VALUE_STRING_ID, 2);
      ((ConfigValueString)configValue).pack(packStream);
    }
    else
    {
      throw new IllegalArgumentException("unknown map value type " +
          configValue.getClass().getSimpleName());
    }
  }


  public @NotNull ConfigValue unpackMapValue(@NotNull PackInputStream packStream)
      throws IOException
  {
    final ConfigValue configValue;

    switch(packStream.readSmall(2))
    {
      case MAP_VALUE_BOOL_ID:
        configValue = ConfigValueBool.unpack(packStream);
        break;

      case MAP_VALUE_MESSAGE_ID:
        configValue = ConfigValueMessage.unpack(this, packStream);
        break;

      case MAP_VALUE_NUMBER_ID:
        configValue = ConfigValueNumber.unpack(packStream);
        break;

      case MAP_VALUE_STRING_ID:
        configValue = ConfigValueString.unpack(packStream);
        break;

      default:
        throw new IllegalStateException("map value expected");
    }

    return mapValues.computeIfAbsent(configValue, identity());
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy