001package jmri.jmrix.ipocs.protocol;
002
003import java.nio.ByteBuffer;
004import java.util.ArrayList;
005import java.util.List;
006
007import org.apache.commons.lang3.SerializationException;
008import org.slf4j.Logger;
009import org.slf4j.LoggerFactory;
010
011import jmri.jmrix.ipocs.protocol.packets.Packet;
012
013/**
014 * Represents a IPOCS Message.
015 *
016 * Protocol details can be found on the project website, https://ipocsmr.github.io
017 *
018 * @author Fredrik Elestedt Copyright (C) 2020
019 * @since 4.21.2
020 */
021public class Message {
022  private final static Logger log = LoggerFactory.getLogger(Message.class);
023  private byte length;
024  private String objectName;
025  private final List<Packet> packets = new ArrayList<Packet>();
026
027  public byte getLength() {
028    return length;
029  }
030
031  public String getObjectName() {
032    return objectName;
033  }
034
035  public void setObjectName(String objectName) {
036      this.objectName = objectName;
037  }
038
039  public List<Packet> getPackets() {
040    return packets;
041  }
042
043  public static Message parse(ByteBuffer buffer, Integer contentSize) {
044    int startPos = buffer.position();
045    Message msg = new Message();
046    // Get length
047    msg.length = buffer.get();
048    // Ensure that there are enough bytes in the buffer:
049    if (msg.length > contentSize) {
050      return null;
051    }
052    // Get object name
053    StringBuilder sb = new StringBuilder();
054    byte last;
055    while ((last = buffer.get()) != 0x00) {
056      sb.append((char) last);
057    }
058    msg.objectName = sb.toString();
059    // Parse packets
060    Packet packet;
061    log.debug("Message for {}", msg.objectName);
062    while (buffer.position() - startPos < msg.length && (packet = Packet.parse(buffer)) != null) {
063      msg.packets.add(packet);
064    }
065    return msg;
066  }
067
068  public ByteBuffer serialize() {
069    ByteBuffer buffer = ByteBuffer.allocate(1 + objectName.length() + 1);
070    buffer.put(length);
071    buffer.put(objectName.getBytes());
072    buffer.put((byte)0);
073    for (Packet packet : packets) {
074      ByteBuffer serPacket = packet.serialize();
075      ByteBuffer oldBuffer = buffer;
076      oldBuffer.rewind();
077      serPacket.rewind();
078      buffer = ByteBuffer.allocate(buffer.capacity() + serPacket.capacity());
079      buffer.put(oldBuffer);
080      buffer.put(serPacket);
081    }
082    if (buffer.capacity() > 0xFF) {
083      throw new SerializationException("Serialized message is longer than protocol allows for.");
084    }
085    buffer.put(0, (byte)buffer.capacity());
086
087    buffer.rewind();
088    return buffer;
089  }
090}