Java tutorial
/** * ***************************************************************************** * Copyright (c) 2016 * <p> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ***************************************************************************** */ package com.exalttech.trex.ui.controllers; import com.cisco.trex.stateless.TRexClient; import com.cisco.trex.stl.gui.storages.StatsStorage; import com.cisco.trex.stl.gui.util.RunningConfiguration; import com.exalttech.trex.application.TrexApp; import com.exalttech.trex.core.*; import com.exalttech.trex.remote.exceptions.IncorrectRPCMethodException; import com.exalttech.trex.remote.exceptions.InvalidRPCResponseException; import com.exalttech.trex.remote.exceptions.PortAcquireException; import com.exalttech.trex.remote.exceptions.TrafficException; import com.exalttech.trex.remote.models.profiles.FlowStats; import com.exalttech.trex.remote.models.profiles.Profile; import com.exalttech.trex.remote.models.validate.StreamValidation; import com.exalttech.trex.ui.MultiplierType; import com.exalttech.trex.ui.PortManagerEventHandler; import com.exalttech.trex.ui.PortState; import com.exalttech.trex.ui.PortsManager; import com.exalttech.trex.ui.components.CustomTreeItem; import com.exalttech.trex.ui.components.CustomTreeItem.TreeItemType; import com.exalttech.trex.ui.components.NotificationPanel; import com.exalttech.trex.ui.controllers.ports.PortView; import com.exalttech.trex.ui.dialog.DialogManager; import com.exalttech.trex.ui.dialog.DialogWindow; import com.exalttech.trex.ui.models.Port; import com.exalttech.trex.ui.models.PortModel; import com.exalttech.trex.ui.models.SystemInfoReq; import com.exalttech.trex.ui.models.datastore.Connection; import com.exalttech.trex.ui.models.datastore.ConnectionsWrapper; import com.exalttech.trex.ui.util.TrexAlertBuilder; import com.exalttech.trex.ui.views.MultiplierOptionChangeHandler; import com.exalttech.trex.ui.views.MultiplierView; import com.exalttech.trex.ui.views.PacketTableUpdatedHandler; import com.exalttech.trex.ui.views.PacketTableView; import com.exalttech.trex.ui.views.logs.LogType; import com.exalttech.trex.ui.views.logs.LogsController; import com.exalttech.trex.ui.views.models.AssignedProfile; import com.exalttech.trex.ui.views.models.ProfileMultiplier; import com.exalttech.trex.ui.views.services.CountdownService; import com.exalttech.trex.ui.views.services.RefreshingService; import com.exalttech.trex.ui.views.statistics.StatsLoader; import com.exalttech.trex.ui.views.statistics.StatsTableGenerator; import com.exalttech.trex.util.Constants; import com.exalttech.trex.util.ProfileManager; import com.exalttech.trex.util.Util; import com.exalttech.trex.util.files.XMLFileManager; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.xored.javafx.packeteditor.events.InitPacketEditorEvent; import com.xored.javafx.packeteditor.events.ScapyClientNeedConnectEvent; import javafx.application.Platform; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.concurrent.Task; import javafx.concurrent.WorkerStateEvent; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.*; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Pane; import javafx.stage.WindowEvent; import javafx.util.Duration; import org.apache.log4j.Logger; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URL; import java.util.*; import java.util.function.Consumer; import java.util.logging.Level; /** * Main view FXML controller * * @author Georgekh */ public class MainViewController implements Initializable, EventHandler<KeyEvent>, MultiplierOptionChangeHandler, PortManagerEventHandler, PacketTableUpdatedHandler { private static final Logger LOG = Logger.getLogger(MainViewController.class.getName()); private final RPCMethods serverRPCMethods = TrexApp.injector.getInstance(RPCMethods.class); private final RunningConfiguration runningConfiguration = TrexApp.injector .getInstance(RunningConfiguration.class); private static final String DISABLED_MULTIPLIER_MSG = "Multiplier is disabled because all streams have latency enabled"; @FXML TreeView devicesTree; @FXML ScrollPane statTableContainer; @FXML AnchorPane statTableWrapper; @FXML AnchorPane profileContainer; @FXML ComboBox<String> profileListBox; @FXML Label profileDetailLabel; @FXML Label disableProfileNote; @FXML AnchorPane profileDetailContainer; @FXML AnchorPane profileTableViewContainer; @FXML AnchorPane mainViewContainer; @FXML MenuItem connectMenuItem; @FXML Label serverStatusLabel; @FXML ImageView serverStatusIcon; @FXML MenuItem statsMenuItem; @FXML MenuItem captureMenuItem; @FXML AnchorPane multiplierOptionContainer; @FXML Pane notificationPanelHolder; @FXML Button updateBtn; @FXML Button stopUpdateBtn; @FXML Button newProfileBtn; @FXML Button duplicateProfileBtn; @FXML AnchorPane logContainer; @FXML Label startStream; @FXML Label startAllStream; @FXML Label stopStream; @FXML Label stopAllStream; @FXML Label pauseStream; @FXML Label acquirePort; @FXML Label releasePort; @FXML Label connectIcon; @FXML Label clearCache; @FXML Label countdownValue; @FXML TabPane logsContainer; @FXML Tab consoleLogTab; @FXML Tab logTab; @FXML Button copyToClipboardBtn; @FXML Label dashboardIcon; @FXML Tooltip connectDixconnectTooltip; @FXML ImageView devicesTreeArrowContainer; @FXML SplitPane mainViewSplitPanel; @FXML PortView portView; @FXML Label serviceModeLabel; BooleanProperty portViewVisibilityProperty = new SimpleBooleanProperty(false); BooleanProperty systemInfoVisibilityProperty = new SimpleBooleanProperty(true); private Optional<ContextMenu> rightClickDevicesTreeMenu = Optional.empty(); private ContextMenu rightClickPortMenu; private ContextMenu rightClickProfileMenu; private ContextMenu rightClickGlobalMenu; private DialogWindow connectWindow; private DialogWindow trafficWindow; private DialogWindow aboutWindow; private DialogWindow captureWindow; private DialogWindow preferencesWindow; private DialogWindow dashboardWindow; private DialogWindow trexDaemonWindow; private SystemInfoReq systemInfoReq = null; private PacketTableView tableView; private RefreshingService refreshStatsService = new RefreshingService(); private final Map<Integer, CustomTreeItem> portTreeItemMap = new HashMap<>(); private final BooleanProperty updateProfileListProperty = new SimpleBooleanProperty(); private final Map<Integer, AssignedProfile> assignedPortProfileMap = new HashMap<>(); private Profile[] loadedProfiles; private String currentSelectedProfile; private MultiplierView multiplierView; private NotificationPanel notificationPanel; boolean needReassignProfile = false; private CountdownService countdownService; private PortsManager portManager; private final BooleanProperty disableProfileProperty = new SimpleBooleanProperty(); StatsTableGenerator statsTableGenerator; private boolean allStreamWithLatency; private boolean isFirstPortStatusRequest = true; private static final String DISCONNECT_MENU_ITEM_TITLE = "Disconnect"; private static final String CONNECT_MENU_ITEM_TITLE = "Connect"; private int lastSelectedPortIndex = -1; private int previousSelectedPortIndex = -1; //TODO reorganize usage of this field private boolean profileLoaded = false; private Image leftArrow; private Image rightArrow; private boolean treeviewOpened = true; private EventBus eventBus; private boolean resetAppInProgress; private BooleanProperty trafficProfileLoadedProperty = new SimpleBooleanProperty(false); private StatsStorage statsStorage; @Override public void initialize(URL url, ResourceBundle rb) { portManager = PortsManager.getInstance(); portManager.setPortManagerHandler(this); statsTableGenerator = new StatsTableGenerator(); leftArrow = new Image("/icons/arrow_left.png"); rightArrow = new Image("/icons/arrow_right.png"); initializeInlineComponent(); logsContainer.setDisable(false); eventBus = TrexApp.injector.getInstance(EventBus.class); statsStorage = TrexApp.injector.getInstance(StatsStorage.class); portView.visibleProperty().bind(portViewVisibilityProperty); statTableContainer.visibleProperty().bindBidirectional(systemInfoVisibilityProperty); ConnectionManager.getInstance().addDisconnectListener(() -> resetApplication(true)); // Handle update port state event AsyncResponseManager.getInstance().asyncEventObjectProperty() .addListener((observable, oldValue, newVal) -> { switch (newVal.getType()) { case PORT_RELEASED: case PORT_ACQUIRED: case PORT_ATTR_CHANGED: case PORT_STARTED: case PORT_STOPPED: final int portId = newVal.getData().getAsJsonPrimitive("port_id").getAsInt(); PortModel portModel = portManager.getPortModel(portId); if (ConnectionManager.getInstance().isConnected()) { Platform.runLater(() -> { portManager.updatedPorts(Arrays.asList(portModel.getIndex())); onPortListUpdated(true); }); } break; case SERVER_STOPPED: resetApplication(true); break; } }); } /** * Handle connect menu item clicked * * @param event */ @FXML public void handleConnectMenuItemClicked(ActionEvent event) { doConnectDisconnect(); } /** * Handle connect button clicked * * @param event */ @FXML public void handleConnectDisconnectBtnClicked(MouseEvent event) { doConnectDisconnect(); } /** * Connect/Disconnect to TRex server */ private void doConnectDisconnect() { if (ConnectionManager.getInstance().isConnected()) { resetApplication(false); } else { openConnectDialog(); } } /** * Handle Exit menu item click * * @param event */ @FXML public void handleExitMenuItemClick(ActionEvent event) { // release all port handleAppClose(); System.exit(0); } /** * Open connect dialog */ private void openConnectDialog() { try { if (connectWindow == null) { connectWindow = new DialogWindow("ConnectDialog.fxml", "Connect", 300, 100, false, TrexApp.getPrimaryStage()); } connectWindow.show(true); if (ConnectionManager.getInstance().isConnected()) { serverRPCMethods.serverApiSync(); loadSystemInfo(); StatsLoader.getInstance().start(); statsStorage.startPolling(); portManager.updatePortForce(); serverStatusLabel.setText("Connected"); serverStatusIcon.setImage(new Image("/icons/connectedIcon.gif")); String disconnectIconStyle = "disconnectIcon"; if (!connectIcon.getStyleClass().contains(disconnectIconStyle)) { connectIcon.getStyleClass().add(disconnectIconStyle); } connectDixconnectTooltip.setText("Disconnect from TRex server"); connectMenuItem.setText(DISCONNECT_MENU_ITEM_TITLE); statsMenuItem.setDisable(false); captureMenuItem.setDisable(false); clearCache.setDisable(false); logsContainer.setDisable(false); copyToClipboardBtn.setDisable(false); dashboardIcon.setDisable(false); } } catch (IOException | NullPointerException ex) { LOG.error("Error while Connecting", ex); } } /** * Run loading system info thread */ private void loadSystemInfo() { LogsController.getInstance().appendText(LogType.INFO, "Loading port information"); String data = ConnectionManager.getInstance().sendRequest("get_system_info", ""); data = Util.removeFirstBrackets(data); systemInfoReq = (SystemInfoReq) Util.fromJSONString(data, SystemInfoReq.class); systemInfoReq.setIp(ConnectionManager.getInstance().getIPAddress()); systemInfoReq.setPort(ConnectionManager.getInstance().getRpcPort()); List<Port> ports = systemInfoReq.getResult().getPorts(); Collections.sort(ports, (p1, p2) -> Integer.compare(p1.getIndex(), p2.getIndex())); portManager.setPortList(ports); String versionResponse = ConnectionManager.getInstance().sendRequest("get_version", ""); Gson gson = new Gson(); JsonObject version = gson.fromJson(versionResponse, JsonArray.class).get(0).getAsJsonObject(); systemInfoReq.getResult() .setApiVersion(version.getAsJsonObject("result").getAsJsonPrimitive("version").getAsString()); LogsController.getInstance().appendText(LogType.INFO, "Loading port information complete"); } /** * Open manage traffic profile dialog * * @param event * @throws IOException */ @FXML public void openTrafficProfile(ActionEvent event) { try { if (trafficWindow == null) { trafficWindow = new DialogWindow("TrafficProfileDialog.fxml", "Traffic Profiles", 10, 50, true, TrexApp.getPrimaryStage()); TrafficProfileDialogController controller = (TrafficProfileDialogController) trafficWindow .getController(); controller.init(); } trafficWindow.show(true); } catch (IOException | NullPointerException ex) { LOG.error("Error opening traffic profile", ex); } } /** * Load and render devices tree * * @throws UnsupportedEncodingException */ private void updateDevicesTree() { if (devicesTree.getRoot() == null) { TreeItem root = new CustomTreeItem("TRex-" + ConnectionManager.getInstance().getIPAddress(), TreeItemType.DEVICES, rightClickGlobalMenu); root.setExpanded(true); portManager.getPortList().stream().forEach(port -> { // build port tree item root.getChildren().add(createPortItem(port)); }); devicesTree.setRoot(root); devicesTree.getSelectionModel().select(0); } else { portManager.getPortList().stream().forEach(port -> { if (portTreeItemMap.get(port.getIndex()) != null) { CustomTreeItem item = portTreeItemMap.get(port.getIndex()); item.setTooltipText(port.getStatus()); item.updateItemValue("Port " + port.getIndex(), port.getOwner(), PortState.getPortStatus(port.getStatus()).getIcon()); } else { devicesTree.getRoot().getChildren().add(createPortItem(port)); } }); } } /** * Render port tree item * * @param port * @return */ private TreeItem createPortItem(Port port) { CustomTreeItem root = new CustomTreeItem("Port " + port.getIndex(), port.getOwner(), PortState.getPortStatus(port.getStatus()).getIcon(), TreeItemType.PORT); root.setTooltipText(port.getStatus()); root.setMenu(rightClickPortMenu); root.setReturnedValue(String.valueOf(port.getIndex())); portTreeItemMap.put(port.getIndex(), root); CustomTreeItem profileItem = new CustomTreeItem("Profile", null, null, TreeItemType.PORT_PROFILE); profileItem.setMenu(rightClickProfileMenu); profileItem.setReturnedValue(String.valueOf(port.getIndex())); root.getChildren().add(profileItem); return root; } /** * Handle tree item clicked * * @param mouseEvent */ @FXML public void handleTreeClicked(MouseEvent mouseEvent) { rightClickDevicesTreeMenu.ifPresent(ContextMenu::hide); CustomTreeItem selected = (CustomTreeItem) devicesTree.getSelectionModel().getSelectedItem(); if (selected != null) { if (mouseEvent.getButton() == MouseButton.SECONDARY) { updateContextMenuState(); rightClickDevicesTreeMenu = Optional.ofNullable(selected.getMenu()); rightClickDevicesTreeMenu.ifPresent(contextMenu -> { contextMenu.show(devicesTree, mouseEvent.getScreenX(), mouseEvent.getScreenY()); }); } } } /** * Handle treeitem selection changed */ private void handleTreeItemSelectionChanged() { updateHeaderBtnStat(); CustomTreeItem selected = (CustomTreeItem) devicesTree.getSelectionModel().getSelectedItem(); // update acquire/release port icon state updateAcquireReleaseBtnState(true); if (selected != null) { if (profileLoaded) { updateCurrentProfile(); } try { stopRefreshingService(); // show table container by default hideShowStatTable(true); portViewVisibilityProperty.setValue(false); systemInfoVisibilityProperty.setValue(false); serviceModeLabel.visibleProperty().unbind(); serviceModeLabel.setVisible(false); switch (selected.getTreeItemType()) { case DEVICES: systemInfoVisibilityProperty.setValue(true); buildSystemInfoTable(); break; case PORT: updateAcquireReleaseBtnState(false); loadPortModel(); portViewVisibilityProperty.setValue(true); break; case PORT_PROFILE: viewProfile(); break; default: break; } } catch (Exception ex) { LOG.error(ex); } } } /** * Update current loaded profile */ private void updateCurrentProfile() { //TODO get rid of this method and implement with tryUpdateProfile(...) profileLoaded = false; AssignedProfile assignedProf = assignedPortProfileMap.get(lastSelectedPortIndex); if (assignedProf != null) { assignedProf.setHasDuration(multiplierView.isDurationEnable()); updateMultiplierValues(assignedProf); } if (isWaitingUpdate()) { tryUpdateProfile(false, true); } } /** * Update right click menu enabling state */ private void updateContextMenuState() { int portId = getSelectedPortIndex(); if (portId != -1) { Port port = portManager.getPortByIndex(portId); boolean isOwned = port.getOwner().equals(ConnectionManager.getInstance().getClientName()); setDisableContextMenuItem("Acquire", !Util.isNullOrEmpty(port.getOwner())); setDisableContextMenuItem("Release Acquire", !isOwned); boolean enableServiceMenuItemDisabled = true; boolean disableServiceMenuItemDisabled = true; if (isOwned) { enableServiceMenuItemDisabled = port.getServiceMode(); disableServiceMenuItemDisabled = !port.getServiceMode(); } setDisableContextMenuItem("Enable Service Mode", enableServiceMenuItemDisabled); setDisableContextMenuItem("Disable Service Mode", disableServiceMenuItemDisabled); } } private void setDisableContextMenuItem(String item, boolean disable) { Optional<MenuItem> disableServiceModeOptional = getItemByName(rightClickPortMenu, item); disableServiceModeOptional.ifPresent(menuItem -> menuItem.setDisable(disable)); } private Optional<MenuItem> getItemByName(ContextMenu menu, String text) { return menu.getItems().stream().filter(menuItem -> menuItem.getText().equalsIgnoreCase(text)).findFirst(); } /** * Reset the application to initial state */ private void resetApplication(boolean didServerCrash) { if (!didServerCrash) { releaseAllPort(false); } if (!resetAppInProgress) { resetAppInProgress = true; portManager.clearPorts(); Platform.runLater(() -> { DialogManager.getInstance().closeAll(); statsStorage.stopPolling(); shutdownRunningServices(); LogsController.getInstance().getView().clear(); profileListBox.getSelectionModel().select(Constants.SELECT_PROFILE); // clear tree devicesTree.setRoot(null); // hide all right side views statTableWrapper.setVisible(false); profileContainer.setVisible(false); serviceModeLabel.visibleProperty().unbind(); serviceModeLabel.setVisible(false); connectMenuItem.setText(CONNECT_MENU_ITEM_TITLE); statsMenuItem.setDisable(true); captureMenuItem.setDisable(true); dashboardIcon.setDisable(true); serverStatusIcon.setImage(new Image("/icons/offline.png")); serverStatusLabel.setText("Disconnected"); connectIcon.getStyleClass().remove("disconnectIcon"); connectDixconnectTooltip.setText("Connect to TRex server"); // reset Header btns startStream.setDisable(true); startAllStream.setDisable(true); stopStream.setDisable(true); stopAllStream.setDisable(true); pauseStream.setDisable(true); clearCache.setDisable(true); logsContainer.setDisable(false); copyToClipboardBtn.setDisable(true); acquirePort.setDisable(true); releasePort.setDisable(true); assignedPortProfileMap.clear(); portViewVisibilityProperty.setValue(false); resetAppInProgress = false; ConnectionManager.getInstance().disconnect(); if (didServerCrash) { TrexAlertBuilder.build().setType(Alert.AlertType.ERROR).setTitle("Disconnected from TRex") .setHeader("Disconnected from TRex server") .setContent("Make sure TRex server is online and reachable.\n" + "If you have a slow connection network connection you can change timeout options in the application connection settings.\n") .getAlert().showAndWait(); openConnectDialog(); } }); } } /** * Build Device table info */ private void buildSystemInfoTable() { statTableContainer.setContent(statsTableGenerator.generateSystemInfoPane(systemInfoReq)); } /** * Build port detail table */ private void loadPortModel() { PortModel model = portManager.getPortModel(getSelectedPortIndex()); serviceModeLabel.visibleProperty().bind(model.serviceModeProperty()); portManager.updatedPorts(Arrays.asList(getSelectedPortIndex())); Optional<Integer> optional = portManager.getOwnedPortIndexes().stream() .filter(idx -> idx.equals(getSelectedPortIndex())).findFirst(); optional.ifPresent(val -> model.setIsOwned(true)); portView.loadModel(model); } /** * Hide and show stat table * * @TODO need to get rid off this method * * @param showStatTable */ private void hideShowStatTable(boolean showStatTable) { statTableContainer.setVisible(true); statTableWrapper.setVisible(showStatTable); profileContainer.setVisible(!showStatTable); } /** * Show profile view */ private void viewProfile() { try { hideShowStatTable(false); int portIndex = getSelectedPortIndex(); lastSelectedPortIndex = portIndex; profileLoaded = true; disableProfileProperty.set(!portManager.isCurrentUserOwner(portIndex)); disableProfileNote.visibleProperty().bind(disableProfileProperty); AssignedProfile assigned = assignedPortProfileMap.get(portIndex); if (assigned == null || !portManager.isCurrentUserOwner(portIndex)) { assigned = new AssignedProfile(); assignedPortProfileMap.put(portIndex, assigned); } if (assigned.isProfileAssigned()) { profileListBox.getSelectionModel().select(assigned.getProfileName()); profileDetailContainer.setVisible(true); } else { profileDetailContainer.setVisible(false); profileListBox.getSelectionModel().select(Constants.SELECT_PROFILE); } tableView.reset(); if (!Util.isNullOrEmpty(assigned.getProfileName())) { loadStreamTable(assigned.getProfileName()); // fill multiplier values multiplierView.fillAssignedProfileValues(assigned); } previousSelectedPortIndex = portIndex; } catch (Exception ex) { LOG.error("Error loading profile", ex); } } /** * Assign profile to selected port * * @param profileName */ private void assignProfile(String profileName, double currentBandwidth, boolean assignPrevBandwidth, int portID) { try { // update selected profile AssignedProfile assignedProf = assignedPortProfileMap.get(portID); if (assignedProf == null) { return; } assignedProf.setProfileName(profileName); assignedProf.setAllStreamsWithLatency(allStreamWithLatency); PortModel port = PortsManager.getInstance().getPortModel(portID); String portState = port.getPortStatus(); StreamValidation streamValidationGraph = serverRPCMethods.assignTrafficProfile(portID, loadedProfiles); portManager.getPortModel(portID).setStreamLoaded(true); startStream.setDisable(false); // update current multiplier data assignedProf.setRate(streamValidationGraph.getResult().getRate()); multiplierView.assignNewProfile(assignedProf); // update multiplier value according to previous bandwidth value if (assignPrevBandwidth) { multiplierView.setSliderValue(currentBandwidth); } updateMultiplierValues(assignedProf); if (portState.equalsIgnoreCase("tx")) { startTraffic(portID); } } catch (IOException | InvalidRPCResponseException | IncorrectRPCMethodException ex) { startStream.setDisable(true); portManager.getPortModel(portID).setStreamLoaded(false); LOG.error("Failed to load Stream", ex); } catch (Exception ex) { java.util.logging.Logger.getLogger(MainViewController.class.getName()).log(Level.SEVERE, null, ex); } finally { portManager.updatedPorts(Arrays.asList(portID)); } } /** * View YAML file stream table data * * @param fileName */ private void loadStreamTable(String fileName) { if (loadProfile(fileName)) { allStreamWithLatency = false; boolean flowStatsEnabled = false; boolean latencyEnabled = false; if (loadedProfiles.length > 0) { allStreamWithLatency = true; for (Profile profile : loadedProfiles) { FlowStats flowStats = profile.getStream().getFlowStats(); allStreamWithLatency = allStreamWithLatency && flowStats.isLatencyEnabled(); flowStatsEnabled = flowStatsEnabled || flowStats.getEnabled(); latencyEnabled = latencyEnabled || flowStats.isLatencyEnabled(); } } runningConfiguration.flowStatsEnabledProperty().set(flowStatsEnabled); runningConfiguration.latencyEnabledProperty().set(latencyEnabled); multiplierView.setDisable(allStreamWithLatency); notificationPanelHolder.setVisible(allStreamWithLatency); } } private boolean loadProfile(String fileName) { try { File selectedFile = new File(ProfileManager.getInstance().getProfileFilePath(fileName)); loadedProfiles = tableView.loadStreamTable(selectedFile); return true; } catch (Exception e) { LOG.error("Error loading stream table", e); LogsController.getInstance().appendText(LogType.ERROR, "Unable to load profile " + fileName); return false; } } /** * Initialize in-line built component */ private void initializeInlineComponent() { updateBtn.setGraphic(new ImageView(new Image("/icons/apply.png"))); newProfileBtn.setGraphic(new ImageView(new Image("/icons/add_profile.png"))); duplicateProfileBtn.setGraphic(new ImageView(new Image("/icons/clone_profile.png"))); stopUpdateBtn.setGraphic(new ImageView(new Image("/icons/stop_update.png"))); devicesTreeArrowContainer.setImage(leftArrow); // mapped profiles enabling with property profileListBox.disableProperty().bind(disableProfileProperty); newProfileBtn.disableProperty().bind(disableProfileProperty); duplicateProfileBtn.disableProperty().bind(disableProfileProperty); profileDetailLabel.disableProperty().bind(disableProfileProperty); profileListBox.getItems().clear(); profileListBox.setItems(FXCollections.observableArrayList(getProfilesNameList())); profileListBox.valueProperty().addListener(new UpdateProfileListener<>(profileListBox.getSelectionModel())); updateProfileListProperty.bind(ProfileManager.getInstance().getUpdatedProperty()); updateProfileListProperty.addListener( (ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> { List<String> profiles = getProfilesNameList(); profileListBox.setItems(FXCollections.observableArrayList(profiles)); if (!profiles.contains(currentSelectedProfile)) { tableView.reset(); profileDetailContainer.setVisible(false); } }); tableView = new PacketTableView(230, this, true); profileTableViewContainer.getChildren().add(tableView); serverStatusIcon.setImage(new Image("/icons/offline.png")); // initialize right click menu rightClickPortMenu = new ContextMenu(); addMenuItem(rightClickPortMenu, "Acquire", ContextMenuClickType.ACQUIRE, false); addMenuItem(rightClickPortMenu, "Force Acquire", ContextMenuClickType.FORCE_ACQUIRE, false); addMenuItem(rightClickPortMenu, "Release Acquire", ContextMenuClickType.RELEASE_ACQUIRE, false); addMenuItem(rightClickPortMenu, "Enable Service Mode", ContextMenuClickType.ENABLE_SERVICE, false); addMenuItem(rightClickPortMenu, "Disable Service Mode", ContextMenuClickType.DISABLE_SERVICE, false); rightClickProfileMenu = new ContextMenu(); addMenuItem(rightClickProfileMenu, "Play", ContextMenuClickType.PLAY, false); addMenuItem(rightClickProfileMenu, "Pause", ContextMenuClickType.PAUSE, false); addMenuItem(rightClickProfileMenu, "Stop", ContextMenuClickType.STOP, false); rightClickGlobalMenu = new ContextMenu(); addMenuItem(rightClickGlobalMenu, "Release All Ports", ContextMenuClickType.RELEASE_ALL, false); addMenuItem(rightClickGlobalMenu, "Acquire All Ports", ContextMenuClickType.ACQUIRE_ALL, false); addMenuItem(rightClickGlobalMenu, "Force Acquire All Ports", ContextMenuClickType.FORCE_ACQUIRE_ALL, false); addMenuItem(rightClickGlobalMenu, "Re-Acquire my Ports", ContextMenuClickType.ACQUIRE_MY_PORT, false); // initialize multiplexer multiplierView = new MultiplierView(this); multiplierOptionContainer.getChildren().add(multiplierView); notificationPanel = new NotificationPanel(); notificationPanel.setNotificationMsg(DISABLED_MULTIPLIER_MSG); notificationPanelHolder.getChildren().add(notificationPanel); // add close TrexApp.getPrimaryStage().setOnCloseRequest(new EventHandler<WindowEvent>() { @Override public void handle(WindowEvent event) { // handle aplpication close DialogManager.getInstance().closeAll(); handleAppClose(); } }); TrexApp.getPrimaryStage().setOnShown(new EventHandler<WindowEvent>() { @Override public void handle(WindowEvent event) { TrexApp.getPrimaryStage().focusedProperty().addListener( (ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> { if (newValue && tableView.isStreamEditingWindowOpen()) { tableView.setStreamEditingWindowOpen(false); streamTableUpdated(); } }); } }); TrexApp.getPrimaryStage().setOnCloseRequest(new EventHandler<WindowEvent>() { @Override public void handle(WindowEvent event) { System.exit(0); } }); logContainer.getChildren().add(LogsController.getInstance().getView()); // initialize countdown service countdownService = new CountdownService(); countdownService.setPeriod(Duration.seconds(Constants.REFRESH_ONE_INTERVAL_SECONDS)); countdownService.setRestartOnFailure(false); countdownService.setOnSucceeded((WorkerStateEvent event) -> { int count = (int) event.getSource().getValue(); countdownValue.setText(String.valueOf(count) + " Sec"); if (count == 0) { doUpdateAssignedProfile(); } }); devicesTree.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue observable, Object oldValue, Object newValue) { handleTreeItemSelectionChanged(); } }); } /** * Handle add new profile * * @param ev */ @FXML public void handleAddNewProfile(ActionEvent ev) { try { String newProfileName = ProfileManager.getInstance().createNewProfile(TrexApp.getPrimaryStage()); if (!Util.isNullOrEmpty(newProfileName)) { profileListBox.getSelectionModel().select(newProfileName); } } catch (IOException ex) { LOG.error("Error creating new profile", ex); } } /** * Handle add new profile * * @param ev */ @FXML public void handleDuplicateProfile(ActionEvent ev) { try { String assignedProfile = String.valueOf(profileListBox.getValue()); if (Util.isNullOrEmpty(assignedProfile) || Constants.SELECT_PROFILE.equals(assignedProfile)) { return; } String duplicatedProfileName = ProfileManager.getInstance().duplicateProfile(TrexApp.getPrimaryStage(), assignedProfile); if (Util.isNullOrEmpty(duplicatedProfileName)) { return; } int portID = getSelectedPortIndex(); if (portID > -1) { if (PortState.getPortStatus(portManager.getPortByIndex(portID).getStatus()) == PortState.PAUSE && !Util.isNullOrEmpty(duplicatedProfileName)) { profileListBox.getSelectionModel().select(duplicatedProfileName); } } } catch (IOException ex) { LOG.error("Error duplicating profile", ex); } } /** * Add menu item * * @param menu * @param text * @param type * @param isDisable */ private MenuItem addMenuItem(ContextMenu menu, String text, ContextMenuClickType type, boolean isDisable) { MenuItem item = new MenuItem(text); item.setDisable(isDisable); item.setOnAction(event -> handleContextMenuItemCLicked(type)); menu.getItems().add(item); return item; } /** * Clear stat cache * * @param event */ @FXML public void clearStatCache(MouseEvent event) { // TODO: fill shadow counters } /** * Handle About tree item clicked * * @param event * @throws java.lang.Exception */ @FXML public void handleAboutTreeItemClicked(ActionEvent event) { try { if (aboutWindow == null) { aboutWindow = new DialogWindow("AboutWindowView.fxml", "TRex", 200, 100, false, TrexApp.getPrimaryStage()); } aboutWindow.show(true); } catch (IOException | NullPointerException ex) { LOG.error("Error opening About", ex); } } /** * Handle stats menu item clicked * * @param event */ @FXML public void handleStatMenuItemClicked(ActionEvent event) { openStateDialog(); } /** * Handle stats menu item clicked * * @param event */ @FXML public void handleCaptureItemClicked(ActionEvent event) { final String currentUser = ConnectionManager.getInstance().getClientName(); Optional<Port> atLeastOneEnabledServiceMode = PortsManager.getInstance().getPortList().stream() .filter(port -> port.getOwner().equalsIgnoreCase(currentUser) && port.getServiceMode()).findAny(); if (atLeastOneEnabledServiceMode.isPresent()) { try { if (captureWindow == null) { captureWindow = new DialogWindow("pkt_capture/Layout.fxml", "Packet Capture", 50, 10, 1200, 700, true, TrexApp.getPrimaryStage()); } captureWindow.show(false); } catch (IOException ex) { LOG.error("Error opening dashboard view", ex); } } else { TrexAlertBuilder.build().setType(Alert.AlertType.ERROR).setTitle("Capture error") .setHeader("Unable to open capture window") .setContent("At least one port with enabled service mode should be acquired").getAlert().show(); } } /** * Handle stats menu item clicked * * @param event */ @FXML public void handleCaptureSettingsItemClicked(ActionEvent event) { } /** * Open statistic dashboard view */ private void openStateDialog() { try { if (dashboardWindow == null) { dashboardWindow = new DialogWindow("dashboard/Dashboard.fxml", "Dashboard", 50, 10, 1210, 740, true, TrexApp.getPrimaryStage()); } dashboardWindow.show(false); } catch (IOException ex) { LOG.error("Error opening dashboard view", ex); } } /** * Handle key down event * * @param event */ @Override public void handle(KeyEvent event) { if (!event.getCharacter().matches("[0-9]") && event.getCode() != KeyCode.BACK_SPACE) { event.consume(); } } /** * start transit button click handler * * @param event */ @FXML public void startTransitBtnCLicked(MouseEvent event) { int portID = getSelectedPortIndex(); LOG.trace("Clicked on the Start Transit Button with selectedPort [" + portID + "]"); if (portID > -1) { doStartResume(portID); } } /** * Do start/Resume port * * @param portID */ private void doStartResume(int portID) { // disable start button to avoid another quick click startStream.setDisable(true); if (PortState.getPortStatus(portManager.getPortByIndex(portID).getStatus()) == PortState.PAUSE) { serverRPCMethods.resumeTraffic(portID); } else { startTraffic(portID); } portManager.updatedPorts(Arrays.asList(portID)); } /** * start all transit button click handler * * @param event */ @FXML public void startAllTransitBtnCLicked(MouseEvent event) { LOG.trace("Clicked on the Start All Transit Button"); portManager.getPortList().stream().forEach(new Consumer<Port>() { @Override public void accept(Port port) { PortState portState = PortState.getPortStatus(port.getStatus()); if (portManager.isCurrentUserOwner(port.getIndex()) && portState != PortState.TX && portState != PortState.IDLE) { doStartResume(port.getIndex()); } } }); } /** * Start traffic on port * * @param portID */ private void startTraffic(int portID) { try { AssignedProfile assignedProf = assignedPortProfileMap.get(portID); if (assignedProf != null && assignedProf.isAllStreamsWithLatency()) { serverRPCMethods.startTraffic(portID, false, "percentage", 100, multiplierView.getDuration()); } else { serverRPCMethods.startTraffic(portID, false, "pps", multiplierView.getPPSValue(), multiplierView.getDuration()); } if (assignedProf != null) { assignedProf.setStreamStarted(true); assignedProf.setHasDuration(multiplierView.isDurationEnable()); updateMultiplierValues(assignedProf); } } catch (TrafficException ex) { // re-enable start button in case of errors startStream.setDisable(false); LOG.error("Error starting traffic", ex); } } /** * stop transit btn clicked * * @param event */ @FXML public void stopTransitBtnCLicked(MouseEvent event) { int portID = getSelectedPortIndex(); LOG.trace("Clicked on the Stop Transit Button with selectedPort [" + portID + "]"); if (portID > -1) { serverRPCMethods.stopPortTraffic(portID); portManager.updatedPorts(Arrays.asList(portID)); if (isWaitingUpdate() && !needReassignProfile) { cancelUpdate(); } } } /** * stop all transit btn clicked * * @param event */ @FXML public void stopAllTransitBtnCLicked(MouseEvent event) { LOG.trace("Clicked on the Stop All Transit Button "); portManager.getPortList().stream().forEach(port -> { PortState portState = PortState.getPortStatus(port.getStatus()); if (portManager.isCurrentUserOwner(port.getIndex()) && portState == PortState.TX) { serverRPCMethods.stopPortTraffic(port.getIndex()); portManager.updatedPorts(Arrays.asList(port.getIndex())); } }); enableUpdateBtn(false, false); } /** * pause transit btn clicked * * @param event */ @FXML public void pauseTransitBtnCLicked(MouseEvent event) { int portID = getSelectedPortIndex(); LOG.trace("Clicked on the Pause Transit Button with selectedPort [" + portID + "]"); if (portID > -1) { if (PortState.getPortStatus(portManager.getPortByIndex(portID).getStatus()) == PortState.PAUSE) { serverRPCMethods.resumeTraffic(portID); } else { enableUpdateBtn(false, false); serverRPCMethods.pauseTraffic(portID); } portManager.updatedPorts(Arrays.asList(portID)); } } /** * Return port index related to selected treeItem * * @return */ private int getSelectedPortIndex() { CustomTreeItem selected = (CustomTreeItem) devicesTree.getSelectionModel().getSelectedItem(); if (selected != null && !Util.isNullOrEmpty(selected.getReturnedValue())) { return Integer.parseInt(selected.getReturnedValue()); } return -1; } /** * Handle context menu item clicked * * @param type */ private void handleContextMenuItemCLicked(ContextMenuClickType type) { try { Integer portIndex = getSelectedPortIndex(); switch (type) { case ENABLE_SERVICE: PortsManager.getInstance().getPortModel(portIndex).serviceModeProperty().set(true); break; case DISABLE_SERVICE: PortsManager.getInstance().getPortModel(portIndex).serviceModeProperty().set(false); break; case ACQUIRE: acquirePort(); break; case FORCE_ACQUIRE: serverRPCMethods.acquireServerPort(portIndex, true); portManager.getPortModel(portIndex).setIsOwned(true); portManager.updatePortForce(); break; case RELEASE_ACQUIRE: releasePort(portIndex, true, true); break; case PLAY: doStartResume(portIndex); break; case PAUSE: serverRPCMethods.pauseTraffic(portIndex); portManager.updatedPorts(Arrays.asList(portIndex)); break; case STOP: serverRPCMethods.stopPortTraffic(portIndex); portManager.updatedPorts(Arrays.asList(portIndex)); break; case ACQUIRE_ALL: acquireAllPorts(false, false); break; case FORCE_ACQUIRE_ALL: acquireAllPorts(true, false); break; case ACQUIRE_MY_PORT: acquireAllPorts(true, true); break; case RELEASE_ALL: releaseAllPort(true); portManager.updatePortForce(); break; case UNLOAD_PROFILE: profileListBox.setValue(Constants.SELECT_PROFILE); break; default: break; } } catch (PortAcquireException ex) { LOG.error("Error handling context menu item clicked", ex); } } /** * Acquire selected port */ private void acquirePort() { try { serverRPCMethods.acquireServerPort(getSelectedPortIndex(), false); portManager.updatePortForce(); portManager.getPortModel(getSelectedPortIndex()).setIsOwned(true); } catch (PortAcquireException ex) { LOG.error("Error acquiring port", ex); } } /** * Release selected port */ private void releasePort(int portIndex, boolean forceUpdatePort, boolean stopTraffic) { serverRPCMethods.releasePort(portIndex, stopTraffic); // remove saved assigned profile if (assignedPortProfileMap.get(portIndex) != null) { assignedPortProfileMap.remove(portIndex); } if (!resetAppInProgress) { final int selectedPortIndex = getSelectedPortIndex(); if (selectedPortIndex != -1) { portManager.getPortModel(selectedPortIndex).setIsOwned(false); } } if (forceUpdatePort) { portManager.updatePortForce(); } } /** * Release all ports */ private void releaseAllPort(boolean stopTraffic) { portManager.getPortList().stream().forEach(port -> { if (PortsManager.getInstance().isCurrentUserOwner(port.getIndex())) { releasePort(port.getIndex(), false, stopTraffic); } }); } /** * Acquire all ports * * @param force * @param acquireOwnedOnly * @throws PortAcquireException */ private void acquireAllPorts(boolean force, boolean acquireOwnedOnly) { for (Port port : portManager.getPortList()) { try { if (!acquireOwnedOnly || (acquireOwnedOnly && portManager.isCurrentUserOwner(port.getIndex()))) { serverRPCMethods.acquireServerPort(port.getIndex(), force); } } catch (PortAcquireException ex) { LOG.error("Error handling context menu item clicked", ex); } } portManager.updatePortForce(); } /** * Handle update button click * * @param event */ @FXML public void handleUpdateBtnClicked(ActionEvent event) { doUpdateAssignedProfile(); } /** * Update current port */ private void doUpdateAssignedProfile() { try { if (needReassignProfile) { needReassignProfile = false; String assignedProfile = String.valueOf(profileListBox.getValue()); assignProfile(assignedProfile, multiplierView.getSliderValue(), true, lastSelectedPortIndex); } else { serverRPCMethods.updateTraffic(lastSelectedPortIndex, false, MultiplierType.pps.name(), multiplierView.getPPSValue()); // update assigned profile multiplier AssignedProfile assignedProf = assignedPortProfileMap.get(lastSelectedPortIndex); updateMultiplierValues(assignedProf); } updateHeaderBtnStat(); } catch (TrafficException ex) { LOG.error("Error updating port", ex); } enableUpdateBtn(false, false); } /** * Update multiplier values * * @param assignedProf */ private void updateMultiplierValues(AssignedProfile assignedProf) { ProfileMultiplier multiplier = new ProfileMultiplier(); multiplier.setDuration(multiplierView.getDuration()); multiplier.setValue(multiplierView.getPPSValue()); multiplier.setSelectedType(multiplierView.getType()); multiplier.setType("pps"); multiplier.setUnit("pps"); assignedProf.setMultiplier(multiplier); } /** * Handle application close */ private void handleAppClose() { try { // stop running thread shutdownRunningServices(); if (!portManager.getPortList().isEmpty() && !portManager.getPortList().isEmpty()) { releaseAllPort(false); } // stop async subscriber if (ConnectionManager.getInstance().isConnected()) { ConnectionManager.getInstance().disconnect(); } } catch (Exception ex) { LOG.error("Error closing the application", ex); System.exit(0); } } /** * Return profile name list * * @return */ private List<String> getProfilesNameList() { List<String> profilenameList = ProfileManager.getInstance().loadProfiles(); profilenameList.add(0, Constants.SELECT_PROFILE); return profilenameList; } /** * Update header stream buttons state */ private void updateHeaderBtnStat() { int portIndex = getSelectedPortIndex(); resetBtnState(); if (portIndex != -1) { Port port = portManager.getPortByIndex(portIndex); PortState state = PortState.getPortStatus(port.getStatus()); // enable state btn btn according to owner boolean isOwner = portManager.isCurrentUserOwner(portIndex); switch (state) { case STREAMS: startStream.setDisable(!isOwner || !portManager.getPortModel(portIndex).isStreamLoaded()); break; case TX: pauseStream.setDisable(!isOwner); stopStream.setDisable(!isOwner); break; case PAUSE: startStream.setDisable(!isOwner); pauseStream.setDisable(!isOwner); stopStream.setDisable(!isOwner); pauseStream.getStyleClass().add("pauseIconPressed"); break; case IDLE: AssignedProfile portProfile = assignedPortProfileMap.get(portIndex); if (portProfile != null) { startStream.setDisable(!(isOwner && portProfile.isProfileAssigned())); } break; default: break; } } } /** * Reset stream header buttons state */ private void resetBtnState() { startStream.setDisable(true); stopStream.setDisable(true); pauseStream.setDisable(true); pauseStream.getStyleClass().remove("pauseIconPressed"); } /** * * @param event */ @FXML public void handlePreferencesMenuItemClicked(ActionEvent event) { openPreferencesWindow(); } /** * Open preferences window */ private void openPreferencesWindow() { try { if (preferencesWindow == null) { preferencesWindow = new DialogWindow("Preferences.fxml", "Preferences", 100, 50, true, TrexApp.getPrimaryStage()); } preferencesWindow.show(true); } catch (IOException ex) { LOG.error("Error opening preferences window", ex); } } /** * Tries to update profile for last selected port. If * this port is transmitting traffic the update will * be delayed ("Update" and "Cancel" buttons will appear), * otherwise update will be executed immediately. * @param enqueueNeedReassign if true, then profile will be reassigned * on update, if false -- only trafficUpdate * will be called. If there is already need * to reassign profile and enqueueNeedReassign is false * it still will be reassigned on next update * @param forceUpdate if true the update will be executed immediately * ignoring other conditions */ private void tryUpdateProfile(boolean enqueueNeedReassign, boolean forceUpdate) { needReassignProfile |= enqueueNeedReassign; boolean shouldDelay = portManager.getPortModel(lastSelectedPortIndex).transmitStateProperty().get() && isContinuousStream(); if (shouldDelay && !forceUpdate) { enableUpdateBtn(true, true); } else { doUpdateAssignedProfile(); } } /** * Overloaded version of {@link #tryUpdateProfile(boolean, boolean)} method * with parameter forceUpdate set to false by default. * @param enqueueNeedReassign */ private void tryUpdateProfile(boolean enqueueNeedReassign) { tryUpdateProfile(enqueueNeedReassign, false); } /** * Cancels update if it was delayed inside {@link #tryUpdateProfile(boolean)} method */ private void cancelUpdate() { enableUpdateBtn(false, false); } /** * Uses with {@link #tryUpdateProfile(boolean)} method * @return true if profile updating was delayed and not yet executed, * returns false otherwise */ private boolean isWaitingUpdate() { return !updateBtn.isDisabled(); } /** * Enable update/Stop button button */ private void enableUpdateBtn(boolean enableCounter, boolean enableUpdate) { stopUpdateBtn.setVisible(enableCounter); countdownValue.setVisible(enableCounter); updateBtn.setDisable(!enableUpdate); if (enableCounter) { countdownService.resetCounter(); countdownService.restart(); } else if (countdownService.isRunning()) { countdownService.cancel(); countdownValue.setText(""); } } /** * Return True if all stream is continuous, otherwise return false * * @return */ private boolean isContinuousStream() { for (Profile pro : loadedProfiles) { if (!"continuous".equals(pro.getStream().getMode().getType())) { return false; } } return true; } /** * Multiplier option value changed handler */ @Override public void optionValueChanged() { if (portManager.getPortModel(getSelectedPortIndex()).transmitStateProperty().get()) tryUpdateProfile(false); } /** * Handle dashboard button clicked * * @param event */ @FXML public void handleDashboardBtnClicked(MouseEvent event) { openStateDialog(); } /** * Handle Stop button clicked * * @param event */ @FXML public void hanldeStopBtnClicked(ActionEvent event) { enableUpdateBtn(false, true); } /** * * @param successfullyUpdated */ @Override public void onPortListUpdated(boolean successfullyUpdated) { if (successfullyUpdated) { updateDevicesTree(); updateHeaderBtnStat(); enableDisableStartStopAllBtn(); if (isFirstPortStatusRequest) { isFirstPortStatusRequest = false; reAcquireOwnedPorts(); } CustomTreeItem selected = (CustomTreeItem) devicesTree.getSelectionModel().getSelectedItem(); if (selected != null && selected.getTreeItemType() == TreeItemType.PORT) { updateAcquireReleaseBtnState(false); } else if (selected != null && selected.getTreeItemType() == TreeItemType.PORT_PROFILE && !portManager.isCurrentUserOwner(getSelectedPortIndex())) { viewProfile(); } } else { LOG.info("Server went down ... handling it"); resetApplication(true); } } /** * Re-acquire owned port on login */ private void reAcquireOwnedPorts() { try { for (Port port : portManager.getPortList()) { if (portManager.isCurrentUserOwner(port.getIndex())) { serverRPCMethods.acquireServerPort(port.getIndex(), true); } } } catch (PortAcquireException ex) { LOG.error("Error re-acquiring port", ex); } } /** * Enable/Disable start/stop all button according to port state */ private void enableDisableStartStopAllBtn() { boolean disableStartStopAll = true; for (Port port : portManager.getPortList()) { if (PortState.getPortStatus(port.getStatus()) != PortState.IDLE) { disableStartStopAll = false; break; } } startAllStream.setDisable(disableStartStopAll); stopAllStream.setDisable(disableStartStopAll); } /** * Copy to clipboard button clicked handler * * @param event */ @FXML public void copyToClipboard(ActionEvent event) { if (logTab.isSelected()) { LogsController.getInstance().getView().copyToClipboard(); return; } } /** * Stop running services */ private void shutdownRunningServices() { portView.stopPolling(); stopRefreshingService(); } /** * Stop refresh service */ private void stopRefreshingService() { if (refreshStatsService.isRunning()) { refreshStatsService.cancel(); } Util.optimizeMemory(); } /** * re-assign profile update button enabled when stream is deleted */ @Override public void onStreamUpdated() { tryUpdateProfile(true); } /** * Stream table changed handler */ @Override public void onStreamTableChanged() { streamTableUpdated(); } /** * Reload stream table */ private void streamTableUpdated() { try { String fileName = String.valueOf(profileListBox.getValue()); loadStreamTable(fileName); // assigned profile may changed need to re-assign tryUpdateProfile(true); } catch (Exception ex) { LOG.error("Error reloading table", ex); } } /** * Handle acquire port button clicked * * @param event */ @FXML public void handleAcquireBtnClicked(MouseEvent event) { acquirePort(); } /** * Handle release port button clicked * * @param event */ @FXML public void handleReleaseBtnClicked(MouseEvent event) { releasePort(getSelectedPortIndex(), true, true); } /** * Update acquire/release port button enabling state */ private void updateAcquireReleaseBtnState(boolean forceDisable) { int selectedPort = getSelectedPortIndex(); if (selectedPort == -1) { return; } acquirePort.setDisable(!(!forceDisable && portManager.isPortFree(selectedPort))); releasePort.setDisable(!(!forceDisable && portManager.isCurrentUserOwner(selectedPort))); } /** * Handle devicestree arrow clicking * * @param event */ @FXML public void handleDevicesTreeArrowClicked(MouseEvent event) { if (treeviewOpened) { mainViewSplitPanel.setDividerPosition(0, 0); devicesTreeArrowContainer.setImage(rightArrow); } else { mainViewSplitPanel.setDividerPosition(0, 1); devicesTreeArrowContainer.setImage(leftArrow); } treeviewOpened = !treeviewOpened; } /** * Handle menu item connect to TRex Daemon * * @param actionEvent */ @FXML public void handleTRexDaemonItemClick(ActionEvent actionEvent) { try { if (trexDaemonWindow == null) { trexDaemonWindow = new DialogWindow("TRexDaemonDialog.fxml", "TRex Daemon", 50, 10, 1200, 750, true, TrexApp.getPrimaryStage()); } trexDaemonWindow.show(false); } catch (IOException ex) { LOG.error("Error opening TRex Daemon view", ex); } } /** * Enumerator that present Context menu item type */ private enum ContextMenuClickType { ACQUIRE, FORCE_ACQUIRE, RELEASE_ACQUIRE, ENABLE_SERVICE, DISABLE_SERVICE, PLAY, STOP, UNLOAD_PROFILE, PAUSE, ACQUIRE_ALL, FORCE_ACQUIRE_ALL, RELEASE_ALL, ACQUIRE_MY_PORT } @Subscribe public void handleScapyClientNeedConnectEvent(ScapyClientNeedConnectEvent event) { LogsController.getInstance().getView().setDisable(false); if (!ConnectionManager.getInstance().isScapyConnected()) { ConnectionsWrapper connection = (ConnectionsWrapper) XMLFileManager.loadXML("connections.xml", ConnectionsWrapper.class); Connection lastUsed = null; for (Connection con : connection.getConnectionList()) { if (con.isLastUsed()) { lastUsed = con; } } if (lastUsed == null) { ConnectionManager.getInstance().connectScapy(); } else { ConnectionManager.getInstance().connectScapy(lastUsed.getIp(), lastUsed.getScapyPort()); } if (!ConnectionManager.getInstance().isScapyConnected()) { openConnectDialog(); } if (ConnectionManager.getInstance().isScapyConnected()) { eventBus.post(new InitPacketEditorEvent()); return; } } } public class UpdateProfileListener<T> implements ChangeListener<T> { private final SelectionModel<T> selectionModel; private boolean reverting = false; public UpdateProfileListener(SelectionModel<T> selectionModel) { if (selectionModel == null) { throw new IllegalArgumentException(); } this.selectionModel = selectionModel; } @Override public void changed(ObservableValue<? extends T> observable, T oldValue, T newValue) { if (reverting || lastSelectedPortIndex != previousSelectedPortIndex) { return; } if (!resetAppInProgress && !isAllowed()) { reverting = true; Platform.runLater(() -> { selectionModel.select(oldValue); reverting = false; }); return; } try { if (isWaitingUpdate()) { tryUpdateProfile(false, true); } String profileName = String.valueOf(newValue); profileDetailContainer.setVisible(false); if (!Util.isNullOrEmpty(profileName) && !Constants.SELECT_PROFILE.equals(profileName)) { profileDetailContainer.setVisible(true); currentSelectedProfile = profileName; loadStreamTable(profileName); tryUpdateProfile(true, true); trafficProfileLoadedProperty.set(true); } else { unloadProfile(); } } catch (Exception ex) { LOG.error("Error loading profile", ex); } } protected boolean isAllowed() { int portIndex = getSelectedPortIndex(); PortModel currentPortModel = portManager.getPortModel(portIndex); boolean isPortTransmit = currentPortModel.transmitStateProperty().get(); if (!isPortTransmit && Constants.SELECT_PROFILE.equals(selectionModel.getSelectedItem())) { return true; } if (isPortTransmit) { String header = "Port " + portIndex + " in TX mode"; String content = "Assigning another profile to the port will stop it. Proceed?"; Optional result = runConfirmationDialog(header, content); return result.isPresent() && result.get() == ButtonType.OK; } return true; } } private void unloadProfile() { if (currentSelectedProfile == null) { return; } Task<Void> unloadProfileTask = new Task<Void>() { @Override protected Void call() throws Exception { TRexClient trexClient = ConnectionManager.getInstance().getTrexClient(); trexClient.stopTraffic(lastSelectedPortIndex); trexClient.removeAllStreams(lastSelectedPortIndex); return null; } }; unloadProfileTask.setOnSucceeded(event -> { LogsController.getInstance().appendText(LogType.INFO, currentSelectedProfile + " profile unloaded"); currentSelectedProfile = Constants.SELECT_PROFILE; assignedPortProfileMap.put(lastSelectedPortIndex, new AssignedProfile()); trafficProfileLoadedProperty.set(false); portManager.updatedPorts(Arrays.asList(lastSelectedPortIndex)); }); LogsController.getInstance().appendText(LogType.INFO, "Unloading " + currentSelectedProfile + " profile"); new Thread(unloadProfileTask).start(); } private Optional runConfirmationDialog(String header, String content) { return TrexAlertBuilder.build().setType(Alert.AlertType.CONFIRMATION).setTitle("Warning").setHeader(header) .setContent(content).setStyle("warning").getAlert().showAndWait(); } }