Development Guide

History

Internal History extension allows developers to use History view and History service in their extensions.

If you want to use History in your extension, you have to obtain HistoryApi. That can be done in Extension.init method using the following code:

petep.PetepExtension: public void init(ExtensionHelper helper)
Optional<HistoryApi> historyApi = Optional.ofNullable((HistoryApi) extensionHelper.getExtension("history"));

HistoryApi

HistoryApi allows you to register history listeners, create history views and obtain history service.

com.warxim.petep.extension.internal.history.HistoryApi
/**
 * API for History extension
 */
@PetepAPI
public interface HistoryApi {
    /**
     * Creates history view for displaying history in JavaFX context.
     * @param filter Initial filter to use in history view
     * @return History view object for managing history view
     */
    HistoryView createView(HistoryFilter filter);

    /**
     * Gets history service for querying history.
     * @return History service
     */
    HistoryService getService();

    /**
     * Registers listener for handling history events.
     * <p>
     *     <b>Note:</b> Listeners are stored using weak references in history module.
     *     Strong reference has to be stored somewhere in the code.
     * </p>
     * @param listener Listener to be registered
     */
    void registerListener(HistoryListener listener);

    /**
     * Unregisters listener from the history extension.
     * @param listener Listener to be unregistered
     */
    void unregisterListener(HistoryListener listener);
}

HistoryService

HistoryService can be used to run various operation on history.

com.warxim.petep.extension.internal.history.service.HistoryService
/**
 * History service is used for querying history.
 */
@PetepAPI
public interface HistoryService {
    /**
     * Saves PDU to history repository
     * @param pdu PDU to be saved
     * @return Completable future for identifier of created PDU
     */
    CompletableFuture<Optional<Long>> savePdu(HistoricPdu pdu);

    /**
     * Gets PDU from history repository
     * @param id PDU identifier
     * @return Completable future for PDU
     */
    CompletableFuture<Optional<HistoricPdu>> getPdu(long id);

    /**
     * Deletes PDU from history repository
     * @param id PDU identifier
     * @return Completable future for boolean that signalizes if the deletion has been completed successfully
     */
    CompletableFuture<Boolean> deletePdu(long id);

    /**
     * Deletes PDUs from history repository
     * @param ids PDU identifiers
     * @return Completable future for list of identifiers of PDUs, which have been successfully deleted
     */
    CompletableFuture<List<Long>> deletePdus(Collection<Long> ids);

    /**
     * Clears the history.
     * @return Completable future signalizing that the history has been cleaned
     */
    CompletableFuture<Void> clearHistory();

    /**
     * Gets all PDUs from history repository
     * @return Completable future for list of obtained PDUs
     */
    CompletableFuture<List<HistoricPdu>> getPdus();

    /**
     * Gets all PDU views from history repository
     * @return Completable future for list of obtained PDU views
     */
    CompletableFuture<List<HistoricPduView>> getPduViews();

    /**
     * Gets PDUs that match given filter from history repository
     * @param filter Filter for filtering PDUs
     * @return Completable future for list of obtained PDUs
     */
    CompletableFuture<List<HistoricPdu>> getPdusByFilter(HistoryFilter filter);

    /**
     * Gets PDU views that match given filter from history repository
     * @param filter Filter for filtering PDU views
     * @return Completable future for list of obtained PDU views
     */
    CompletableFuture<List<HistoricPduView>> getPduViewsByFilter(HistoryFilter filter);

    /**
     * Gets PDU identifiers that match given filter from history repository
     * @param filter Filter for filtering PDU identifiers
     * @return Completable future for list of obtained PDU identifiers
     */
    CompletableFuture<Set<Long>> getPduIdsByFilter(HistoryFilter filter);

    /**
     * Gets all proxies from history repository
     * @return Completable future for list of obtained proxies
     */
    CompletableFuture<List<HistoricProxy>> getProxies();

    /**
     * Gets all interceptors from history repository
     * @return Completable future for list of obtained proxies
     */
    CompletableFuture<List<HistoricInterceptor>> getInterceptors();

    /**
     * Gets all connections from history repository
     * @return Completable future for list of obtained proxies
     */
    CompletableFuture<List<HistoricConnection>> getConnections();

    /**
     * Gets all tags from history repository
     * @return Completable future for list of obtained proxies
     */
    CompletableFuture<Set<String>> getTags();
}

HistoryView

HistoryView can be used to display history in extensions. It can be created using HistoryApi and should be destroyed using destroy() method.

com.warxim.petep.extension.internal.history.gui.view.HistoryView
/**
 * History view is component for rendering PDU history in GUI.
 * <p>History view is automatically connected with the extension and refreshed.</p>
 * <p>After the view is not needed, destroy should be called, so that listeners are correctly unregistered.</p>
 */
@PetepAPI
public interface HistoryView {
    /**
     * Get JavaFX node for history view.
     * @return JavaFX node that contains the whole HistoryView (table with historic items, PDU view, filter)
     */
    Node getNode();

    /**
     * Get history filter.
     * @return Currently used HistoryFilter that filters items, which are added to the view
     */
    HistoryFilter getFilter();

    /**
     * Sets history filter.
     * <p>This automatically refreshes the items, so that there are all items matching the filter.</p>
     * @param filter New HistoryFilter to be used for filtering items, which are added to the view
     */
    void setFilter(HistoryFilter filter);

    /**
     * Destroys the view.
     * <p>This method should be called after the view is not needed anymore, because it handles unregistration of listeners etc.</p>
     */
    void destroy();
}

HistoryFilter

HistoryFilter can be used to filter history items.

com.warxim.petep.extension.internal.history.model.HistoryFilter
/**
 * History filter for filtering PDUs in history extension.
 * <p><b>Note:</b> PduView cannot be filtered using data filter.</p>
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@PetepAPI
public class HistoryFilter {
    /**
     * Filter by PDU destination
     */
    private PduDestination destination;
    /**
     * Filter by proxy using the database identifier
     */
    private Long proxyId;
    /**
     * Filter by interceptor using the database identifier
     */
    private Long interceptorId;
    /**
     * Filter by connection using the database identifier
     */
    private Long connectionId;
    /**
     * Filter by minimum PDU size
     */
    private Integer fromSize;
    /**
     * Filter by maximum PDU size
     */
    private Integer toSize;
    /**
     * Filter by tags
     */
    private Set<String> tags;
    /**
     * Filter by data
     */
    private byte[] data;
    /**
     * Charset of data provided in {@link HistoryFilter#data}
     */
    private Charset dataCharset;
    /**
     * Type of data filter {@link HistoryFilter#data}
     */
    private DataFilterType dataFilterType;
    /**
     * Should data filter be used as negative search {@link HistoryFilter#data}
     */
    private boolean dataFilterNegative;

    /**
     * Checks whether the provided pduView complies the filter.
     * <p><b>Warning: Since {@link HistoricPduView} does not contain data buffer, it ignores data filter field.</b></p>
     * @param pduView PDU view to check
     * @return {@code true} if pduView complies with the filter
     */
    public boolean matches(HistoricPduView pduView) {
        if (destination != null && pduView.getDestination() != destination) {
            return false;
        }

        if (proxyId != null && !proxyId.equals(pduView.getProxyId())) {
            return false;
        }

        if (interceptorId != null && !interceptorId.equals(pduView.getInterceptorId())) {
            return false;
        }

        if (connectionId != null && !connectionId.equals(pduView.getConnectionId())) {
            return false;
        }

        if (fromSize != null && fromSize > pduView.getSize()) {
            return false;
        }

        if (toSize != null && toSize < pduView.getSize()) {
            return false;
        }

        return tags == null || pduView.getTags().containsAll(tags);
    }

    /**
     * Checks whether the provided pdu complies the filter.
     * @param pdu PDU to check against filter
     * @return {@code true} if pduView complies with the filter
     */
    public boolean matches(HistoricPdu pdu) {
        if (destination != null && pdu.getDestination() != destination) {
            return false;
        }

        if (proxyId != null && !proxyId.equals(pdu.getProxy().getId())) {
            return false;
        }

        if (interceptorId != null && !interceptorId.equals(pdu.getInterceptor().getId())) {
            return false;
        }

        if (connectionId != null && !connectionId.equals(pdu.getConnection().getId())) {
            return false;
        }

        if (fromSize != null && fromSize > pdu.getSize()) {
            return false;
        }

        if (toSize != null && toSize < pdu.getSize()) {
            return false;
        }

        if (tags != null && !pdu.getTags().containsAll(tags)) {
            return false;
        }

        if (data != null) {
            boolean result;
            if (dataFilterType == DataFilterType.STARTS_WITH) {
                result = BytesUtils.startsWith(pdu.getData(), pdu.getSize(), data);
            } else if (dataFilterType == DataFilterType.ENDS_WITH) {
                result = BytesUtils.endsWith(pdu.getData(), pdu.getSize(), data);
            } else {
                // CONTAINS is default
                result = BytesUtils.contains(pdu.getData(), pdu.getSize(), data);
            }
            return dataFilterNegative != result;
        }

        return true;
    }

    /**
     * Checks whether the filter is empty.
     * @return {@code true} if the filter is empty (no filtering is set)
     */
    public boolean isEmpty() {
        if (destination != null) {
            return false;
        }

        if (proxyId != null) {
            return false;
        }

        if (interceptorId != null) {
            return false;
        }

        if (connectionId != null) {
            return false;
        }

        if (fromSize != null) {
            return false;
        }

        if (toSize != null) {
            return false;
        }

        if (tags != null && !tags.isEmpty()) {
            return false;
        }

        return data == null;
    }

    /**
     * Generates filter for getting all PDUs.
     * @return History filter
     */
    public static HistoryFilter all() {
        return new HistoryFilter();
    }

    /**
     * Type of data filter
     */
    public enum DataFilterType {
        /**
         * Checks whether the historic PDU contains specified data.
         */
        CONTAINS,
        /**
         * Checks whether the historic PDU starts with specified data.
         */
        STARTS_WITH,
        /**
         * Checks whether the historic PDU ends with specified data.
         */
        ENDS_WITH
    }
}

HistoryListener

HistoryListener can be used to listen for history events.

com.warxim.petep.extension.internal.history.listener.HistoryListener
/**
 * History listener for listening to events of History.
 * <p>There are create, delete and clear events produced.</p>
 * <p>Listeners can be registered through {@link com.warxim.petep.extension.internal.history.service.HistoryService}.</p>
 * <p>Since these listeners are stored as weak references, strong reference should be kept somewhere in the code.</p>
 */
@PetepAPI
public interface HistoryListener {
    /**
     * Handles creation of historic PDU.
     * @param pdu Created PDU, which has been persisted to database
     * @param pduView View of the created PDU
     */
    default void onHistoricPduCreate(HistoricPdu pdu, HistoricPduView pduView) {}

    /**
     * Handles deletion of historic PDUs.
     * @param ids Collection of identifiers of PDUs, which have been deleted
     */
    default void onHistoricPduDelete(Collection<Long> ids) {}

    /**
     * Handles deletion of all historic items (PDUs, tags, ...).
     */
    default void onHistoryClear() {}
}

Models

There are multiple history data models. HistoricPdu, HistoricConnection and so on. There is also so-called HistoryPduView that contains only few items that are required for HistoryView panel.

com.warxim.petep.extension.internal.history.model.HistoricPdu
/**
 * Historic PDU model
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@PetepAPI
public class HistoricPdu {
    /**
     * Identifier of the PDU in the database
     */
    private Long id;
    /**
     * Originating proxy
     */
    private HistoricProxy proxy;
    /**
     * Originating connection
     */
    private HistoricConnection connection;
    /**
     * Originating interceptor (where the PDU has been recorded)
     */
    private HistoricInterceptor interceptor;
    /**
     * Destination of the PDU
     */
    private PduDestination destination;
    /**
     * Set of PDU tags
     */
    private Set<String> tags;
    /**
     * Size of PDU data
     */
    private int size;
    /**
     * Time when the PDU has been recorded
     */
    private Instant time;
    /**
     * Charset of the data
     */
    private Charset charset;
    /**
     * Data
     */
    private byte[] data;
    /**
     * Serialized metadata (key = metadata name, value = metadata value)
     */
    private Map<String, String> metadata;
}
com.warxim.petep.extension.internal.history.model.HistoricProxy
/**
 * Historic proxy model
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@PetepAPI
public class HistoricProxy {
    /**
     * Identifier of the proxy in the database
     */
    private Long id;
    /**
     * Code of the proxy
     */
    private String code;
    /**
     * Name of the proxy
     */
    private String name;
}
com.warxim.petep.extension.internal.history.model.HistoricConnection
/**
 * Historic connection model
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@PetepAPI
public class HistoricConnection {
    /**
     * Identifier of the connection in the database
     */
    private Long id;
    /**
     * Code of the connection
     */
    private String code;
    /**
     * Name of the connection
     */
    private String name;
}
com.warxim.petep.extension.internal.history.model.HistoricInterceptor
/**
 * Historic interceptor model
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@PetepAPI
public class HistoricInterceptor {
    /**
     * Identifier of the interceptor in the database
     */
    private Long id;
    /**
     * Code of the interceptor
     */
    private String code;
    /**
     * Name of the interceptor
     */
    private String name;
}
com.warxim.petep.extension.internal.history.model.HistoricPduView
/**
 * Historic pdu view model
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@PetepAPI
public class HistoricPduView {
    /**
     * Identifier of the PDU
     */
    private long id;
    /**
     * Identifier of the originating proxy in the database
     */
    private long proxyId;
    /**
     * Name of the originating proxy
     */
    private String proxyName;
    /**
     * Identifier of the originating connection in the database
     */
    private long connectionId;
    /**
     * Name of the originating connection
     */
    private String connectionName;
    /**
     * Identifier of the originating connection in the database (where the PDU has been recorded)
     */
    private long interceptorId;
    /**
     * Name of the originating interceptor
     */
    private String interceptorName;
    /**
     * Destination of the PDU
     */
    private PduDestination destination;
    /**
     * Set of PDU tags
     */
    private Set<String> tags;
    /**
     * Size of PDU data
     */
    private int size;
    /**
     * Time when the PDU has been recorded
     */
    private Instant time;
}