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}