com.exalttech.trex.ui.views.importPcap.ImportedPacketTableView.java Source code

Java tutorial

Introduction

Here is the source code for com.exalttech.trex.ui.views.importPcap.ImportedPacketTableView.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.exalttech.trex.ui.views.importPcap;

import com.exalttech.trex.remote.models.profiles.Profile;
import com.exalttech.trex.ui.components.TextFieldTableViewCell;
import com.exalttech.trex.ui.models.PacketInfo;
import com.exalttech.trex.ui.views.models.ImportPcapTableData;
import com.exalttech.trex.ui.views.streams.builder.PacketBuilderHelper;
import com.exalttech.trex.ui.views.streams.builder.VMInstructionBuilder;
import com.exalttech.trex.ui.views.streams.builder.VMInstructionBuilder.InstructionType;
import com.exalttech.trex.ui.views.streams.viewer.PacketParser;
import com.exalttech.trex.util.TrafficProfile;
import com.exalttech.trex.util.Util;
import java.io.EOFException;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeoutException;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Alert;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import javafx.util.Callback;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.pcap4j.core.NotOpenException;
import org.pcap4j.core.PcapHandle;
import org.pcap4j.core.PcapNativeException;
import org.pcap4j.core.Pcaps;
import org.pcap4j.packet.Packet;

/**
 * Imported packet table view implementation
 *
 * @author GeorgeKH
 */
public class ImportedPacketTableView extends AnchorPane {

    private static final Logger LOG = Logger.getLogger(ImportedPacketTableView.class.getName());

    @FXML
    TableColumn selectedColumn;
    @FXML
    TableColumn nameColumn;
    @FXML
    TableColumn packetNumColumn;
    @FXML
    TableColumn lengthColumn;
    @FXML
    TableColumn macSrcColumn;
    @FXML
    TableColumn macDstColumn;
    @FXML
    TableColumn ipSrcColumn;
    @FXML
    TableColumn ipDstColumn;
    @FXML
    TableColumn packetTypeColumn;
    @FXML
    TableView<ImportPcapTableData> importedStreamTable;

    List<Profile> profilesList;
    List<String> existingNamesList = new ArrayList<>();
    TrafficProfile trafficProfile;
    String yamlFileName;
    ObservableList<ImportPcapTableData> tableDataList = FXCollections.observableArrayList();
    ObservableList<Integer> highlightRows = FXCollections.observableArrayList();
    CheckBox selectAll;
    HighlightedRowFactory<ImportPcapTableData> highlightedRowFactory;
    Map<String, ImportPcapTableData> duplicateRowNamesMap = new HashMap<>();
    int index = 0;
    ImportedPacketProperties propertiesBinder;
    ImportPcapTableData firstPacket = null;

    /**
     * Constructor
     *
     * @param profilesList
     * @param yamlFileName
     */
    public ImportedPacketTableView(List<Profile> profilesList, String yamlFileName) {
        this.profilesList = profilesList;
        this.yamlFileName = yamlFileName;
        trafficProfile = new TrafficProfile();
        highlightedRowFactory = new HighlightedRowFactory<>(highlightRows);
        initView();
    }

    /**
     * Initialize view
     */
    private void initView() {
        try {
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/ImportedPacketTableView.fxml"));
            fxmlLoader.setRoot(this);
            fxmlLoader.setController(this);
            fxmlLoader.load();

            initTableRowsColumns();
            extractExistingNames();
        } catch (Exception ex) {
            LOG.error("Error setting UI", ex);
        }
    }

    /**
     * Set properties binder model
     *
     * @param propertiesBinder
     */
    public void setPropertiesBinder(ImportedPacketProperties propertiesBinder) {
        this.propertiesBinder = propertiesBinder;
        PacketUpdater.getInstance().setImportedProperties(propertiesBinder);
    }

    /**
     * Initialize table rows and columns
     */
    private void initTableRowsColumns() {

        selectedColumn.setCellValueFactory(new PropertyValueFactory<>("selected"));
        selectedColumn.setCellFactory(CheckBoxTableCell.forTableColumn(selectedColumn));
        selectAll = new CheckBox();
        selectAll.getStyleClass().add("selectAll");
        selectAll.setSelected(true);
        selectAll.selectedProperty().addListener(
                (ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
                    selectAllRows();
                });
        selectedColumn.setGraphic(selectAll);

        nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
        nameColumn.setCellFactory(new TextFieldTableViewCell());

        packetNumColumn.setCellValueFactory(new PropertyValueFactory<>("index"));
        lengthColumn.setCellValueFactory(new PropertyValueFactory<>("length"));
        macSrcColumn.setCellValueFactory(new PropertyValueFactory<>("macSrc"));
        macDstColumn.setCellValueFactory(new PropertyValueFactory<>("macDst"));
        ipSrcColumn.setCellValueFactory(new PropertyValueFactory<>("ipSrc"));
        ipDstColumn.setCellValueFactory(new PropertyValueFactory<>("ipDst"));
        packetTypeColumn.setCellValueFactory(new PropertyValueFactory<>("packetType"));

        importedStreamTable.setRowFactory(highlightedRowFactory);

    }

    /**
     * Select all rows
     */
    public void selectAllRows() {
        for (ImportPcapTableData item : tableDataList) {
            item.setSelected(selectAll.isSelected());
        }
    }

    /**
     * Extract stream names from existing profile
     */
    private void extractExistingNames() {
        for (Profile profile : profilesList) {
            existingNamesList.add(profile.getName());
        }
    }

    /**
     * Parse pcap file to get all streams
     *
     * @param pcapFile
     * @return
     */
    public boolean setPcapFile(File pcapFile) {
        List<PacketInfo> packetInfoList = new ArrayList<>();
        try {
            PacketUpdater.getInstance().reset();
            PcapHandle handler = Pcaps.openOffline(pcapFile.getAbsolutePath());
            PacketParser parser = new PacketParser();
            Packet packet;
            while ((packet = handler.getNextPacketEx()) != null) {
                if (!PacketUpdater.getInstance().validatePacket(packet)) {
                    break;
                }
                PacketInfo packetInfo = new PacketInfo();
                packet = PacketUpdater.getInstance().updatePacketSrcDst(packet);
                packetInfo.setPacket(packet);
                packetInfo.setTimeStamp(handler.getTimestamp().getTime());
                parser.parsePacket(packet, packetInfo);
                packetInfoList.add(packetInfo);
            }
        } catch (EOFException e) {
            LOG.info("End of pcap file");

        } catch (PcapNativeException | TimeoutException | NotOpenException ex) {
            LOG.error("Error parsing selectd pcap file", ex);
        }
        setTableData(packetInfoList);
        return PacketUpdater.getInstance().isValidPacket();
    }

    /**
     * Set table data
     *
     * @param packetInfoList
     */
    private void setTableData(List<PacketInfo> packetInfoList) {

        index = 1;
        tableDataList.clear();
        for (PacketInfo packetInfo : packetInfoList) {
            ImportPcapTableData tableData = new ImportPcapTableData();
            tableData.setName("packet_" + index);
            tableData.setIndex(index);
            tableData.setLength(packetInfo.getPacket().length());
            tableData.setMacSrc(packetInfo.getSrcMac());
            tableData.setMacDst(packetInfo.getDestMac());
            tableData.setIpSrc(packetInfo.getSrcIpv4());
            tableData.setIpDst(packetInfo.getDestIpv4());
            tableData.setPacketType(trafficProfile.getPacketTypeText(packetInfo.getPacket()).getType());
            tableData.setPacket(packetInfo.getPacket());
            tableData.setHasVlan(packetInfo.hasVlan());
            tableData.setTimeStamp(packetInfo.getTimeStamp());
            tableDataList.add(tableData);
            index++;
        }
        importedStreamTable.setItems(tableDataList);
    }

    /**
     * Import pcap to current yaml file
     *
     * @return
     */
    public boolean doImport() {
        try {
            if (validateStreamNames()) {
                index = 0;
                ImportPcapTableData current = getNextSelectedPacket();
                firstPacket = current;
                ImportPcapTableData next = null;
                boolean firstStream = true;
                long diffTimeStamp = 1;
                while (index <= tableDataList.size()) {
                    if (current != null) {
                        Profile profile = new Profile();
                        profile.setName(current.getName());
                        profile.getStream().getMode().setType("single_burst");
                        String hexDataString = PacketBuilderHelper.getPacketHex(current.getPacket().getRawData());
                        profile.getStream().getPacket()
                                .setBinary(trafficProfile.encodeBinaryFromHexString(hexDataString));

                        // add vm
                        profile.getStream().setAdditionalProperties(getVm(current));
                        // update pps/ISG
                        defineISG_PPSValues(profile, getIpg(diffTimeStamp, firstStream));
                        if (firstStream) {
                            firstStream = false;
                        }
                        // get next stream 
                        next = getNextSelectedPacket();
                        if (next != null && next != current) {
                            profile.setNext(next.getName());
                            diffTimeStamp = next.getTimeStamp() - current.getTimeStamp();
                        } else if (propertiesBinder.getCount() > 0) {
                            profile.setNext(firstPacket.getName());
                            profile.getStream().setActionCount(propertiesBinder.getCount());
                        }

                        current = next;
                        profilesList.add(profile);
                    }
                }

                // save yaml data
                String yamlData = trafficProfile
                        .convertTrafficProfileToYaml(profilesList.toArray(new Profile[profilesList.size()]));
                FileUtils.writeStringToFile(new File(yamlFileName), yamlData);
                return true;
            }
        } catch (Exception ex) {
            LOG.error("Error saving Yaml file", ex);
        }
        return false;
    }

    /**
     * Get next selected stream
     *
     * @return
     */
    private ImportPcapTableData getNextSelectedPacket() {
        if (index == tableDataList.size()) {
            index++;
            return null;
        }
        ImportPcapTableData tableData = tableDataList.get(index);
        index++;
        if (tableData.isSelected()) {
            return tableData;
        }
        return getNextSelectedPacket();
    }

    /**
     * Validate stream names
     *
     * @return
     */
    private boolean validateStreamNames() {

        ObservableList<Integer> duplicateIndexesList = FXCollections.observableArrayList();
        duplicateRowNamesMap.clear();
        // validate saved stream names
        for (ImportPcapTableData tableData : tableDataList) {
            if (tableData.isSelected()) {
                // comparing with existing streams
                if ((existingNamesList.contains(tableData.getName())
                        || Util.isNullOrEmpty(tableData.getName().trim()))) {
                    addDuplicateIndex(duplicateIndexesList, tableData);
                }
                // compairing with other streams in list
                if (duplicateRowNamesMap.get(tableData.getName()) != null) {
                    // name is duplicate
                    addDuplicateIndex(duplicateIndexesList, tableData);
                    addDuplicateIndex(duplicateIndexesList, duplicateRowNamesMap.get(tableData.getName()));
                } else {
                    // add existing names in imported table
                    duplicateRowNamesMap.put(tableData.getName(), tableData);
                }
            }
        }

        highlightedRowFactory.getRowsToHighlight().setAll(duplicateIndexesList);
        boolean validNames = true;
        if (!duplicateIndexesList.isEmpty()) {
            validNames = false;
            Alert alert = Util.getAlert(Alert.AlertType.ERROR);
            alert.setContentText(
                    "Some packet names (highlighted in red) have the same names of exisiting packets !");
            alert.showAndWait();
        }
        return validNames;
    }

    /**
     * Add index to duplicate list
     * @param duplicateIndexesList
     * @param tableData 
     */
    private void addDuplicateIndex(ObservableList<Integer> duplicateIndexesList, ImportPcapTableData tableData) {
        if (!duplicateIndexesList.contains(tableData.getIndex())) {
            duplicateIndexesList.add(tableData.getIndex());
        }
    }

    /**
     * Build vm instructions for source/destination ipv4
     *
     * @param packetData
     * @return
     */
    public Map<String, Object> getVm(ImportPcapTableData packetData) {
        VMInstructionBuilder vmInstructionBuilder = new VMInstructionBuilder(packetData.hasVlan(),
                packetData.getPacketType().indexOf("UDP") != -1);
        ArrayList<Object> instructionsList = new ArrayList<>();

        if (propertiesBinder.isDestinationEnabled()) {
            instructionsList.addAll(vmInstructionBuilder.addVmInstruction(
                    getInstructionType(packetData, propertiesBinder.getDstAddress()), propertiesBinder.getDstMode(),
                    propertiesBinder.getDstCount(), "1", propertiesBinder.getDstAddress()));
        }
        if (propertiesBinder.isSourceEnabled()) {
            instructionsList.addAll(vmInstructionBuilder.addVmInstruction(
                    getInstructionType(packetData, propertiesBinder.getSrcAddress()), propertiesBinder.getSrcMode(),
                    propertiesBinder.getSrcCount(), "1", propertiesBinder.getSrcAddress()));
        }

        // add ipv4 checksum instructions
        instructionsList.addAll(vmInstructionBuilder.addChecksumInstruction());

        Map<String, Object> additionalProperties = new HashMap<>();

        LinkedHashMap<String, Object> vmBody = new LinkedHashMap<>();
        vmBody.put("split_by_var", vmInstructionBuilder.getSplitByVar());
        vmBody.put("instructions", instructionsList);

        // add cache size
        vmInstructionBuilder.addCacheSize(vmBody);

        additionalProperties.put("vm", vmBody);

        return additionalProperties;
    }

    /**
     * Return instruction type according to place of selected address
     *
     * @param packetData
     * @param ipAddress
     * @return
     */
    private InstructionType getInstructionType(ImportPcapTableData packetData, String ipAddress) {
        if (ipAddress.equals(packetData.getIpSrc())) {
            return InstructionType.IP_SRC;
        }
        return InstructionType.IP_DST;
    }

    /**
     * Define ISG/PPS values
     *
     * @param profile
     * @param ipg
     */
    private void defineISG_PPSValues(Profile profile, double ipg) {
        profile.getStream().setIsg(ipg * 1000);
        if (ipg == 0) {
            ipg = 1;
        }
        double ppsValue = Double.parseDouble(Util.formatDecimal(1 / ipg));
        if (ppsValue < 1.0) {
            ppsValue = 1.0;
        }
        profile.getStream().getMode().setPps(ppsValue);
    }

    /**
     * Calculate and return IPG value
     *
     * @param diffTimestamp
     * @param firstStream
     * @return
     */
    private double getIpg(long diffTimestamp, boolean firstStream) {
        if (propertiesBinder.isIPGSelected()) {
            return propertiesBinder.getIpg();

        } else if (firstStream) {
            return 1;
        } else {
            double ipg_usage = (double) diffTimestamp / 1000;
            double ipg = ipg_usage / propertiesBinder.getSpeedup();
            return ipg;
        }
    }

    /**
     * HighlightedRowFactory factory implementation
     *
     * @param <T>
     */
    public class HighlightedRowFactory<T> implements Callback<TableView<T>, TableRow<T>> {

        ObservableList<Integer> rowsToHighlight;

        public HighlightedRowFactory(ObservableList<Integer> rowsToHighlight) {
            this.rowsToHighlight = rowsToHighlight;
        }

        public ObservableList<Integer> getRowsToHighlight() {
            return rowsToHighlight;
        }

        @Override
        public TableRow call(TableView param) {
            TableRow row = new TableRow();

            row.itemProperty().addListener(new ChangeListener() {
                @Override
                public void changed(ObservableValue observable, Object oldValue, Object newValue) {
                    updateRowStyle(row);
                }
            });

            rowsToHighlight.addListener(new ListChangeListener<Integer>() {
                @Override
                public void onChanged(ListChangeListener.Change<? extends Integer> c) {
                    updateRowStyle(row);
                }
            });

            return row;
        }

        /**
         * Update row higlighted style
         *
         * @param row
         */
        private void updateRowStyle(TableRow row) {
            if (row != null && row.getItem() != null) {
                row.getStyleClass().remove("highlightedRow");
                int index = ((ImportPcapTableData) row.getItem()).getIndex();

                if (rowsToHighlight.contains(index)) {
                    row.getStyleClass().add("highlightedRow");
                }
            }
        }
    }
}