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

net.sf.jrtps.message.Data Maven / Gradle / Ivy

package net.sf.jrtps.message;

import java.nio.ByteBuffer;

import net.sf.jrtps.message.data.DataEncapsulation;
import net.sf.jrtps.message.parameter.ParameterEnum;
import net.sf.jrtps.message.parameter.ParameterList;
import net.sf.jrtps.message.parameter.StatusInfo;
import net.sf.jrtps.transport.RTPSByteBuffer;
import net.sf.jrtps.types.EntityId_t;
import net.sf.jrtps.types.SequenceNumber_t;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * This Submessage notifies the RTPS Reader of a change to a data-object belonging to the RTPS Writer. 
 * The possible changes include both changes in value as well as changes to the lifecycle of the data-object.
 * 
 * see 8.3.7.2
 * 
 * @author mcr70
 * 
 */
public class Data extends SubMessage {
	public static final int KIND = 0x15;
	
	private static final Logger log = LoggerFactory.getLogger(Data.class);
	
	private short extraFlags = 0;
	private EntityId_t readerId;
	private EntityId_t writerId;
	private SequenceNumber_t writerSN;
	private ParameterList inlineQosParams;
	private DataEncapsulation dataEncapsulation;
	
	
	/**
	 * Constructor for creating a Data message.
	 * 
	 * @param readerId
	 * @param writerId
	 * @param seqNum
	 * @param inlineQosParams Inline QoS parameters. May be null.
	 * @param dEnc
	 */
	public Data(EntityId_t readerId, EntityId_t writerId, long seqNum,
			ParameterList inlineQosParams, DataEncapsulation dEnc) {
		
		super(new SubMessageHeader(0x15));
		
		this.readerId = readerId;
		this.writerId = writerId;
		this.writerSN = new SequenceNumber_t(seqNum);
		
		if (inlineQosParams != null && inlineQosParams.size() > 0) {
			header.flags |= 0x2;
			this.inlineQosParams = inlineQosParams;
		}

		if (dEnc.containsData()) {
			header.flags |= 0x4; // dataFlag	
		}
		else {
			header.flags |= 0x8; // keyFlag
		}

		this.dataEncapsulation = dEnc;
	}
	
	/**
	 * Constructor to read Data sub-message from RTPSByteBuffer.
	 * 
	 * @param smh
	 * @param bb
	 */
	Data(SubMessageHeader smh, RTPSByteBuffer bb) {
		super(smh);
		
		if (dataFlag() && keyFlag()) {
			// Should we just ignore this message instead
			throw new IllegalStateException("This version of protocol does not allow Data submessage to contain both serialized data and serialized key (9.4.5.3.1)");
		}
		
		int start_count = bb.position(); // start of bytes read so far from the beginning
		
		this.extraFlags = (short) bb.read_short();
		int octetsToInlineQos = bb.read_short() & 0xffff;
		
		int currentCount = bb.position(); // count bytes to inline qos
		
		this.readerId = EntityId_t.readEntityId(bb);
		this.writerId = EntityId_t.readEntityId(bb);
		this.writerSN = new SequenceNumber_t(bb);
				
		int bytesRead = bb.position() - currentCount;
		int unknownOctets = octetsToInlineQos - bytesRead;
		
		for (int i = 0; i < unknownOctets; i++) {
			// TODO: Instead of looping, we should do just
			// newPos = bb.getBuffer.position() + unknownOctets or something like that
			bb.read_octet(); // Skip unknown octets, @see 9.4.5.3.3 octetsToInlineQos
		}
		
		if (inlineQosFlag()) {
			log.trace("Reading inline QoS");
			this.inlineQosParams = new ParameterList(bb);
		}
		
		if (dataFlag() || keyFlag()) { 
			bb.align(4); // Each submessage is aligned on 32-bit boundary, @see 9.4.1 Overall Structure
			int end_count = bb.position(); // end of bytes read so far from the beginning
			
			byte[] serializedPayload = null;
			if (header.submessageLength != 0) {
				serializedPayload = new byte[header.submessageLength - (end_count-start_count)];
			}
			else { // SubMessage is the last one. Rest of the bytes are read. @see 8.3.3.2.3
				ByteBuffer buffer = bb.getBuffer();
				serializedPayload = new byte[buffer.capacity() - buffer.position()];
			}
			
			log.trace("Serialized payload starts at {}, {} bytes", end_count, serializedPayload.length);
			bb.read(serializedPayload);
			dataEncapsulation = DataEncapsulation.createInstance(serializedPayload);
		}
	}
	
	/**
	 * Indicates to the Reader the presence of a ParameterList
	 * containing QoS parameters that should be used to interpret the message.
	 * 
	 * @return true, if inlineQos flag is set
	 */
	public boolean inlineQosFlag() {
		return (header.flags & 0x2) != 0;
	}

	/**
	 * Gets the inlineQos parameters if present. Inline QoS parameters are present, if 
	 * inlineQosFlag() returns true.
	 * 
	 * @see #inlineQosFlag()
	 * @return InlineQos parameters, or null if not present
	 */
	public ParameterList getInlineQos() {
		return inlineQosParams;
	}

	public boolean isDisposed() {
		if (inlineQosFlag()) {
			StatusInfo sInfo = (StatusInfo) inlineQosParams.getParameter(ParameterEnum.PID_STATUS_INFO);
			return sInfo.isDisposed();
		}
	
		return false;
	}
	
	public boolean isUnregistered() {
		if (inlineQosFlag()) {
			StatusInfo sInfo = (StatusInfo) inlineQosParams.getParameter(ParameterEnum.PID_STATUS_INFO);
			return sInfo.isUnregistered();
		}
	
		return false;
	}
	
	/**
	 * Indicates to the Reader that the dataPayload submessage element
	 * contains the serialized value of the data-object.
	 * 
	 * @return true, data flag is set
	 */
	public boolean dataFlag() {
		return (header.flags & 0x4) != 0;
	}

	/**
	 * Indicates to the Reader that the dataPayload submessage element
	 * contains the serialized value of the key of the data-object.
	 * 
	 * @return true, if key flag is set
	 */
	public boolean keyFlag() {
		return (header.flags & 0x8) != 0;
	}
	
	
	/**
	 * Identifies the RTPS Reader entity that is being informed of the change to the data-object.
	 * 
	 * @return EntityId_t of the reader
	 */
	public EntityId_t getReaderId() {
		return readerId;
	}

	/**
	 * Identifies the RTPS Writer entity that made the change to the data-object.
	 * 
	 * @return EntityId_t of the writer
	 */
	public EntityId_t getWriterId() {
		return writerId;
	}

	/**
	 * Uniquely identifies the change and the relative order for all
	 * changes made by the RTPS Writer identified by the writerGuid.
	 * Each change gets a consecutive sequence number. Each RTPS
	 * Writer maintains is own sequence number.
	 * 
	 * @return sequence number
	 */
	public long getWriterSequenceNumber() {
		return writerSN.getAsLong();
	}

	

	
	public  short getExtraFlags() {
		return extraFlags;
	}

	@Override
	public void writeTo(RTPSByteBuffer buffer) {
		buffer.write_short(extraFlags);
		
		short octets_to_inline_qos = EntityId_t.LENGTH + EntityId_t.LENGTH + SequenceNumber_t.LENGTH;  
		buffer.write_short(octets_to_inline_qos);

		readerId.writeTo(buffer);
		writerId.writeTo(buffer);
		writerSN.writeTo(buffer);
		
		if (inlineQosFlag()) {
			inlineQosParams.writeTo(buffer);
		}		

		if (dataFlag() || keyFlag()) { 
			buffer.align(4);
			buffer.write(dataEncapsulation.getSerializedPayload()); // TODO: check this
		}
	}


	public DataEncapsulation getDataEncapsulation() {
		return dataEncapsulation;
	}

	/**
	 * Get the StatusInfo inline QoS parameter if it is present. If inline Qos
	 * is not present, an empty(default) StatusInfo is returned
	 * 
	 * @return StatusInfo
	 */
	public StatusInfo getStatusInfo() {
		StatusInfo sInfo = null;
		if (inlineQosFlag()) {
			sInfo = (StatusInfo) inlineQosParams.getParameter(ParameterEnum.PID_STATUS_INFO);
		}
		
		if (sInfo == null) {
			sInfo = new StatusInfo(); // return empty StatusInfo (WRITE)
		}
		
		return sInfo;
	}
	
	
	public String toString() {
		StringBuffer sb = new StringBuffer(super.toString());
		sb.append(", readerId: ").append(getReaderId());
		sb.append(", writerId: ").append(getWriterId());
		sb.append(", writerSN: ").append(writerSN);
		
		if (inlineQosFlag()) {
			sb.append(", inline QoS: ").append(inlineQosParams);
		}
		
		return sb.toString();
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy