Development Guide

Connection

Connection is created in proxies and its purpose is to handle connection between client ⇄ proxy ⇄ server. It reads data from client/server and sends it to PETEP using process method and writes data to client/server from queues.

In order to manage connections, you have to implement ConnectionManager or use the one of default connection manager classes.

Connection interface

com.warxim.petep.core.connection.Connection
/**
 * Connection in PETEP proxy has to handle both connection between client and proxy and between proxy and server.
 */
@PetepAPI
public interface Connection {
    /**
     * Obtains connection code
     * @return Connection code
     */
    String getCode();

    /**
     * Obtains connection parent proxy
     * @return Parent proxy
     */
    Proxy getProxy();

    /**
     * Sends PDU outside PETEP
     * @param pdu PDU to be sent
     */
    void send(PDU pdu);

    /**
     * Checks whether the PDU is supported by this connection.
     * @param pdu PDU to be checked
     * @return {@code true} if the connection supports the specified pdu
     */
    boolean supports(PDU pdu);

    /**
     * Converts connection to displayable string (e.g. in JavaFX components)
     * @return Displayable description of connection
     */
    String toString();

    /**
     * Starts connection.
     * <p>
     *     <b>Warning:</b> this method should return ASAP - it should be used to create threads and then return immediately.
     * </p>
     * @return {@code true} if the start was successful
     */
    boolean start();

    /**
     * Stops connection.
     */
    void stop();
}

Connection base

com.warxim.petep.core.connection.ConnectionBase
/**
 * ConnectionBase is an abstract implementation of Connection, which uses two queues for outgoing data
 * and implements most of the required methods.
 */
@PetepAPI
public abstract class ConnectionBase implements Connection {
    /**
     * Unique identifier of the connection.
     */
    protected final String code;

    /**
     * Parent proxy.
     */
    protected final Proxy proxy;

    /**
     * Outgoing queue in direction C2S (client -&gt; server).
     */
    protected final PduQueue queueC2S;

    /**
     * Outgoing queue in direction S2C (client &lt;- server).
     */
    protected final PduQueue queueS2C;

    /**
     * Constructs connection.
     * @param code Unique code of the connection
     * @param proxy Proxy to which the connection belongs
     */
    protected ConnectionBase(String code, Proxy proxy) {
        this.code = code;
        this.proxy = proxy;
        this.queueC2S = new PduQueue();
        this.queueS2C = new PduQueue();
    }

    @Override
    public String getCode() {
        return code;
    }

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

    @Override
    public void send(PDU pdu) {
        if (pdu.getDestination() == PduDestination.SERVER) {
            queueC2S.add(pdu);
        } else {
            queueS2C.add(pdu);
        }
    }

    @Override
    public boolean supports(PDU pdu) {
        return proxy.supports(pdu);
    }

    /**
     * About connection.
     */
    @Override
    public String toString() {
        return "Connection '" + code + '\'';
    }

    /**
     * Starts connection.
     * <p>
     *     <b>Warning:</b> this method should return ASAP - it should be used to create threads and then return immediately.
     * </p>
     * @return {@code true} if the start was successful
     */
    @Override
    public abstract boolean start();

    /**
     * Stops connection.
     */
    @Override
    public abstract void stop();

    /**
     * Processes PDU in PETEP
     * <p>Puts PDU into internal PETEP processing, which consists of various configured interceptors.</p>
     * @param pdu PDU to be processed
     */
    protected void process(PDU pdu) {
        proxy.getHelper().processPdu(pdu);
    }
}

Connection Manager interface

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.

com.warxim.petep.core.connection.ConnectionManager
/**
 * Interface of connection manager that is used by internal or external modules to work with connections of a given proxy.
 * <p>
 *     All methods should call appropriate listener methods through PetepHelper,
 *     for example, when adding connection - onConnectionStart should be called.
 * </p>
 */
@PetepAPI
public interface ConnectionManager {
    /**
     * Obtains connection by code.
     * @param code Code of connection to be obtained
     * @return Connection or empty optional, if no connection exist with specified code
     */
    Optional<Connection> get(String code);

    /**
     * Adds connection to the connection manager.
     * @param connection Connection to be added
     * @return {@code true} if the connection was successfully added
     */
    boolean add(Connection connection);

    /**
     * Removes connection from the connection manager.
     * @param connection Connection to be removed
     * @return {@code true} if the connection was successfully removed (if it was present in the manager)
     */
    boolean remove(Connection connection);

    /**
     * Removes connection from the connection manager.
     * @param code Code of connection to be removed
     * @return Connection or empty optional, if no connection existed with specified code
     */
    Optional<Connection> remove(String code);

    /**
     * Get list of connections.
     * @return List of connections
     */
    List<Connection> getList();

    /**
     * Stops all connections.
     */
    void stop();
}

Integer Based Connection Manager class

Integer Based Connection Manager class is build on top of concurrent hashmap that uses integer identifier as the key.

com.warxim.petep.core.connection.IntegerBasedConnectionManager
/**
 * Default connection manager that uses ConcurrentHashMap for connection storage and Integer as connection code.
 * <p>
 *     Does not call start/stop on connection, but calls listener onStart/onStop, when connection is added/removed.
 * </p>
 */
@PetepAPI
public class IntegerBasedConnectionManager implements ConnectionManager {
    /**
     * PETEP helper for currently running core.
     */
    protected final PetepHelper helper;

    /**
     * Connection listener for reporting new connections etc.
     */
    protected final ConnectionListener listener;

    /**
     * Map of connections.
     */
    protected final ConcurrentHashMap<Integer, Connection> connections;

    /**
     * ID of last connection.
     */
    private final AtomicInteger lastId;

    /**
     * Constructs connection manager based on integer codes.
     * @param helper PETEP helper for currently running core
     */
    public IntegerBasedConnectionManager(PetepHelper helper) {
        this.helper = helper;
        listener = helper.getConnectionListener();
        connections = new ConcurrentHashMap<>();
        lastId = new AtomicInteger(0);
    }

    @Override
    public Optional<Connection> get(String code) {
        return Optional.ofNullable(connections.get(Integer.parseInt(code)));
    }

    /**
     * {@inheritDoc}
     * <p>
     *  <b>Note:</b> Does not start the connection, but reports it as started to listener.
     * </p>
     * @param connection Connection to be added
     * @return {@code true} if the connection was successfully added
     */
    @Override
    public boolean add(Connection connection) {
        if (connections.putIfAbsent(Integer.parseInt(connection.getCode()), connection) == null) {
            listener.onConnectionStart(connection);
            return true;
        }
        return false;
    }

    /**
     * {@inheritDoc}
     * <p>
     *  <b>Note:</b> Does not stop the connection, but reports it as stopped to listener.
     * </p>
     * @param connection Connection to be removed
     * @return {@code true} if the connection was successfully removed (if it was present in the manager)
     */
    @Override
    public boolean remove(Connection connection) {
        if (connections.remove(Integer.parseInt(connection.getCode()), connection)) {
            listener.onConnectionStop(connection);
            return true;
        }
        return false;
    }

    /**
     * {@inheritDoc}
     * <p>
     *  <b>Note:</b> Does not stop the connection, but reports it as stopped to listener.
     * </p>
     * @param code Code of connection to be removed (automatically converted to integer)
     * @return Connection or empty optional, if no connection existed with specified code
     */
    @Override
    public Optional<Connection> remove(String code) {
        var connection = connections.remove(Integer.parseInt(code));
        if (connection != null) {
            listener.onConnectionStop(connection);
        }
        return Optional.ofNullable(connection);
    }

    @Override
    public List<Connection> getList() {
        return new ArrayList<>(connections.values());
    }

    @Override
    public void stop() {
        connections.values().parallelStream().forEach(Connection::stop);
    }

    /**
     * Generates new id for connection.
     * @return (Last ID + 1) converted to string.
     */
    public String nextCode() {
        return String.valueOf(lastId.incrementAndGet());
    }
}

String Based Connection Manager class

String Based Connection Manager class is build on top of concurrent hashmap that uses string identifier as the key.

com.warxim.petep.core.connection.StringBasedConnectionManager
/**
 * Default connection manager that uses ConcurrentHashMap for connection storage and any String as connection code.
 * <p>
 *     Does not call start/stop on connection, but calls listener onStart/onStop, when connection is added/removed.
 * </p>
 */
@PetepAPI
public class StringBasedConnectionManager implements ConnectionManager {
    /**
     * PETEP helper for currently running core.
     */
    protected final PetepHelper helper;

    /**
     * Connection listener for reporting new connections etc.
     */
    protected final ConnectionListener listener;

    /**
     * Map of connections.
     */
    protected final ConcurrentHashMap<String, Connection> connections;

    /**
     * Constructs connection manager based on string codes.
     * @param helper PETEP helper for currently running core
     */
    public StringBasedConnectionManager(PetepHelper helper) {
        this.helper = helper;
        listener = helper.getConnectionListener();
        connections = new ConcurrentHashMap<>();
    }

    @Override
    public Optional<Connection> get(String code) {
        return Optional.ofNullable(connections.get(code));
    }

    /**
     * {@inheritDoc}
     * <p>
     *  <b>Note:</b> Does not start the connection, but reports it as started to listener.
     * </p>
     * @param connection Connection to be added
     * @return {@code true} if the connection was successfully added
     */
    @Override
    public boolean add(Connection connection) {
        if (connections.putIfAbsent(connection.getCode(), connection) == null) {
            listener.onConnectionStart(connection);
            return true;
        }
        return false;
    }

    /**
     * {@inheritDoc}
     * <p>
     *  <b>Note:</b> Does not stop the connection, but reports it as stopped to listener.
     * </p>
     * @param connection Connection to be removed
     * @return {@code true} if the connection was successfully removed (if it was present in the manager)
     */
    @Override
    public boolean remove(Connection connection) {
        if (connections.remove(connection.getCode(), connection)) {
            listener.onConnectionStop(connection);
            return true;
        }
        return false;
    }

    /**
     * {@inheritDoc}
     * <p>
     *  <b>Note:</b> Does not stop the connection, but reports it as stopped to listener.
     * </p>
     * @param code Code of connection to be removed
     * @return Connection or empty optional, if no connection existed with specified code
     */
    @Override
    public Optional<Connection> remove(String code) {
        var connection = connections.remove(code);
        if (connection != null) {
            listener.onConnectionStop(connection);
        }
        return Optional.ofNullable(connection);
    }

    @Override
    public List<Connection> getList() {
        return new ArrayList<>(connections.values());
    }

    @Override
    public void stop() {
        connections.values().parallelStream().forEach(Connection::stop);
    }

}

Connection listener

Warning: Listeners are persisted using weak references, so you have to keep the strong reference yourself (avoid lambdas).

com.warxim.petep.core.listener.ConnectionListener
/**
 * ConnectionListener allows code to listen for connection start/stop events.
 * <p>
 *     All event handlers should be called from ConnectionManager.
 * </p>
 */
@PetepAPI
public interface ConnectionListener {
    /**
     * Event for connection start.
     * @param connection Connection that started
     */
    default void onConnectionStart(Connection connection) {}

    /**
     * Event for connection stop.
     * @param connection Connection that stopped
     */
    default void onConnectionStop(Connection connection) {}
}