Development Guide

PDU

PDUs (Protocol Data Units) are units used to transmit data through PETEP. They contain operational data (tags, destination, connection, ...), data bytes and you can expand them by adding your own protocol-specific data.

PDU interface

com.warxim.petep.core.pdu.PDU
/**
 * PDU (Protocol Data Unit) is core unit for data processed in PETEP
 */
@PetepAPI
public interface PDU {
    /**
     * Checks if the PDU contain specified tag.
     * @param tag Tag to be checked
     * @return {@code true} if the PDU has the specified tag
     */
    boolean hasTag(String tag);

    /**
     * Adds tag to the PDU.
     * @param tag Tag to be added
     */
    void addTag(String tag);

    /**
     * Removes tag from the PDU.
     * @param tag Tag to be removed
     */
    void removeTag(String tag);

    /**
     * Adds tags to the PDU.
     * @param tags Tags to be added to the PDU
     */
    void addTags(Collection<String> tags);

    /**
     * Obtains tags.
     * @return Set of tags
     */
    Set<String> getTags();

    /**
     * Obtains parent proxy.
     * @return Proxy from which this PDU is coming
     */
    Proxy getProxy();

    /**
     * Sets parent proxy.
     * @param proxy Proxy to be set
     */
    void setProxy(Proxy proxy);

    /**
     * Obtains PDU destination.
     * @return Destination of the PDU
     */
    PduDestination getDestination();

    /**
     * Sets PDU destination.
     * @param destination Destination of the PDU
     */
    void setDestination(PduDestination destination);

    /**
     * Obtains connection.
     * @return Connection that will handle sending of this PDU
     */
    Connection getConnection();

    /**
     * Sets connection.
     * @param connection Connection that will handle sending of this PDU
     */
    void setConnection(Connection connection);

    /**
     * Obtains last interceptor.
     * @return Last interceptor that processed this PDU
     */
    Interceptor getLastInterceptor();

    /**
     * Sets last interceptor.
     * @param lastInterceptor Last interceptor that processed this PDU
     */
    void setLastInterceptor(Interceptor lastInterceptor);

    /**
     * Get the data buffer.
     * @return The whole byte buffer used to store data (can be bigger that the data inside it)
     */
    byte[] getBuffer();

    /**
     * Get size of data in the buffer.
     * @return Size of the data
     */
    int getSize();

    /**
     * Set the buffer
     * @param buffer new byte array buffer to be used
     * @param size size of the data in provided buffer
     */
    void setBuffer(byte[] buffer, int size);

    /**
     * Resizes the buffer.
     * @param size New size of the buffer
     */
    void resize(int size);

    /**
     * Get the charset of the PDU.
     * @return Charset of the data in the buffer
     */
    Charset getCharset();

    /**
     * Sets the charset of the PDU.
     * <p><b>Note:</b> Does not convert the data, just sets the charset property of PDU.</p>
     * @param charset Charset of the PDU
     */
    void setCharset(Charset charset);

    /**
     * Creates deep copy of the PDU.
     * @return Deep copy of the PDU
     */
    PDU copy();
}

Default PDU class

You do not have to create your own PDU class and you can use or extend DefaultPdu class that builds PDU on top of byte arrays.

Do not forget to override copy method when you extend DefaultPdu.

com.warxim.petep.core.pdu.DefaultPdu
/**
 * Default PDU implementation.
 * <p>Uses simple byte array for data buffer.</p>
 * <p>By default uses charset specified in {@link Constant#DEFAULT_CHARSET}.</p>
 */
@PetepAPI
public class DefaultPdu implements PDU {
    /**
     * Parent proxy.
     */
    protected Proxy proxy;
    /**
     * Parent connection.
     */
    protected Connection connection;
    /**
     * PDU destination.
     */
    protected PduDestination destination;
    /**
     * Interceptor in which was the PDU processed the last time.
     */
    protected Interceptor lastInterceptor;
    /**
     * PDU tags.
     */
    protected Set<String> tags;
    /**
     * Data buffer
     */
    protected byte[] buffer;
    /**
     * Size of the data in the buffer
     */
    protected int size;
    /**
     * Charset of the data in the buffer
     */
    protected Charset charset;

    /**
     * Constructs default PDU.
     * @param proxy Proxy
     * @param connection Connection
     * @param destination Destination of the PDU
     * @param buffer Data buffer
     * @param size Size of the data in the buffer
     * @param charset Charset of the data in the buffer
     * @param tags Set of tags
     */
    public DefaultPdu(Proxy proxy, Connection connection, PduDestination destination, byte[] buffer, int size, Charset charset, Set<String> tags) {
        this.proxy = proxy;
        this.destination = destination;
        this.connection = connection;
        this.tags = tags;
        this.buffer = buffer;
        this.size = size;
        this.charset = charset;
    }

    /**
     * Constructs default PDU with default charset.
     * @param proxy Proxy
     * @param connection Connection
     * @param destination Destination of the PDU
     * @param buffer Data buffer
     * @param size Size of the data in the buffer
     * @param tags Set of tags
     */
    public DefaultPdu(Proxy proxy, Connection connection, PduDestination destination, byte[] buffer, int size, Set<String> tags) {
        this(proxy, connection, destination, buffer, size, Constant.DEFAULT_CHARSET, tags);
    }

    /**
     * Constructs default PDU with empty tag set.
     * @param proxy Proxy
     * @param connection Connection
     * @param destination Destination of the PDU
     * @param buffer Data buffer
     * @param size Size of the data in the buffer
     * @param charset Charset of the data in the buffer
     */
    public DefaultPdu(Proxy proxy, Connection connection, PduDestination destination, byte[] buffer, int size, Charset charset) {
        this(proxy, connection, destination, buffer, size, charset, new HashSet<>());
    }

    /**
     * Constructs default PDU with default charset and empty tag set.
     * @param proxy Proxy
     * @param connection Connection
     * @param destination Destination of the PDU
     * @param buffer Data buffer
     * @param size Size of the data in the buffer
     */
    public DefaultPdu(Proxy proxy, Connection connection, PduDestination destination, byte[] buffer, int size) {
        this(proxy, connection, destination, buffer, size, Constant.DEFAULT_CHARSET, new HashSet<>());
    }

    @Override
    public byte[] getBuffer() {
        return buffer;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public Charset getCharset() {
        return charset;
    }

    @Override
    public void setCharset(Charset charset) {
        this.charset = charset;
    }

    @Override
    public void setBuffer(byte[] buffer, int size) {
        this.buffer = buffer;
        this.size = size;
    }

    /**
     * Resizes the buffer (expands the buffer when needed, but does not shrink the buffer).
     * <p>Creates new byte array and copies existing buffer to it, if the buffer has to be expanded.</p>
     * @param size Size of the data buffer
     */
    @Override
    public void resize(int size) {
        if (size <= buffer.length) {
            return;
        }

        byte[] newBuffer = new byte[size];

        // Copy content of original buffer to new one.
        System.arraycopy(buffer, 0, newBuffer, 0, this.size);

        buffer = newBuffer;
    }

    @Override
    public PDU copy() {
        var pdu = new DefaultPdu(proxy, connection, destination, buffer.clone(), size, charset);

        pdu.addTags(tags);
        pdu.setLastInterceptor(pdu.getLastInterceptor());

        return pdu;
    }

    @Override
    public boolean hasTag(String tag) {
        return tags.contains(tag);
    }

    @Override
    public void addTag(String tag) {
        tags.add(tag);
    }

    @Override
    public void removeTag(String tag) {
        tags.remove(tag);
    }

    @Override
    public void addTags(Collection<String> tags) {
        this.tags.addAll(tags);
    }

    @Override
    public Set<String> getTags() {
        return tags;
    }

    @Override
    public Proxy getProxy() {
        return proxy;
    }

    @Override
    public void setProxy(Proxy proxy) {
        this.proxy = proxy;
    }

    @Override
    public PduDestination getDestination() {
        return destination;
    }

    @Override
    public void setDestination(PduDestination destination) {
        this.destination = destination;
    }

    @Override
    public Connection getConnection() {
        return connection;
    }

    @Override
    public void setConnection(Connection connection) {
        this.connection = connection;
    }

    @Override
    public Interceptor getLastInterceptor() {
        return lastInterceptor;
    }

    @Override
    public void setLastInterceptor(Interceptor lastInterceptor) {
        this.lastInterceptor = lastInterceptor;
    }
}

PDU Queue class

PDU queues are blocking queues used in various places in PETEP.

com.warxim.petep.core.pdu.PduQueue
/**
 * Queue of PDUs.
 * <p>Based on {@link BlockingQueue}.</p>
 */
@PetepAPI
public class PduQueue {
    private final BlockingQueue<PDU> queue;

    /**
     * Constructs PDU queue.
     */
    public PduQueue() {
        queue = new LinkedBlockingQueue<>();
    }

    /**
     * Add PDU to queue.
     * @param pdu PDU to be added to the queue
     */
    public void add(PDU pdu) {
        queue.add(pdu);
    }

    /**
     * Obtains PDU from queue (blocks until there is PDU).
     * @return PDU from queue
     * @throws InterruptedException If interrupted while waiting
     */
    public PDU take() throws InterruptedException {
        return queue.take();
    }

    /**
     * Obtains and removes the head of the queue.
     * @return PDU from queue or empty optional if the queue is empty
     */
    public Optional<PDU> poll() {
        return Optional.ofNullable(queue.poll());
    }

    /**
     * Get queue size.
     * @return Size of the queue
     */
    public int size() {
        return queue.size();
    }

    /**
     * Clears queue.
     */
    public void clear() {
        queue.clear();
    }

    /**
     * Checks if the queue is empty.
     * @return {@code true} if the queue is empty
     */
    public boolean isEmpty() {
        return queue.isEmpty();
    }
}

Serialized PDU

Serialized PDUs are standard way of serializing PDUs to persistable format. (It contains codes of proxies, connections, serialized metadata etc.)

com.warxim.petep.core.pdu.SerializedPdu
/**
 * Simple object representing serialized PDU.
 * <p>All PDU fields represented by data types, which can be serialized by PETEP.</p>
 * <p>Can be displayed by {@link com.warxim.petep.gui.control.SerializedPduView}.</p>
 * <p>Can be user for storing PDUs as part of configuration/store.</p>
 */
@Data
@Builder
@PetepAPI
public class SerializedPdu {
    /**
     * Proxy serialized as proxy code.
     */
    private String proxy;
    /**
     * Connection serialized as connection code.
     */
    private String connection;
    /**
     * Interceptor serialized as interceptor code.
     */
    private String interceptor;
    private PduDestination destination;
    private byte[] buffer;
    @Builder.Default
    private Charset charset = Constant.DEFAULT_CHARSET;
    @Builder.Default
    private Set<String> tags = new HashSet<>();
    /**
     * Map of serialized metadata (key = metadata name, value = metadata value)
     */
    @Builder.Default
    private Map<String, String> metadata = new HashMap<>();

    /**
     * Creates deep copy of the serialized PDU.
     * @return Deep copy of the serialized PDU
     */
    public SerializedPdu copy() {
        return SerializedPdu.builder()
                .proxy(proxy)
                .connection(connection)
                .interceptor(interceptor)
                .destination(destination)
                .buffer(buffer.clone())
                .charset(charset)
                .tags(new HashSet<>(tags))
                .metadata(new HashMap<>(metadata))
                .build();
    }
}