com.net2plan.gui.utils.onlineSimulationPane.OnlineSimulationPane.java Source code

Java tutorial

Introduction

Here is the source code for com.net2plan.gui.utils.onlineSimulationPane.OnlineSimulationPane.java

Source

/*******************************************************************************
 * Copyright (c) 2015 Pablo Pavon Mario.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl.html
 * <p>
 * Contributors:
 * Pablo Pavon Mario - initial API and implementation
 ******************************************************************************/

package com.net2plan.gui.utils.onlineSimulationPane;

import static com.net2plan.internal.sim.SimCore.SimState.NOT_STARTED;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.PriorityQueue;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.RowSorter;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.border.LineBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.text.DefaultCaret;

import org.apache.commons.collections15.BidiMap;

import com.jom.JOMException;
import com.net2plan.gui.utils.AdvancedJTable;
import com.net2plan.gui.utils.CellRenderers;
import com.net2plan.gui.utils.ClassAwareTableModel;
import com.net2plan.gui.utils.ColumnFitAdapter;
import com.net2plan.gui.utils.IVisualizationCallback;
import com.net2plan.gui.utils.ParameterValueDescriptionPanel;
import com.net2plan.gui.utils.ProportionalResizeJSplitPaneListener;
import com.net2plan.gui.utils.ReportBrowser;
import com.net2plan.gui.utils.RunnableSelector;
import com.net2plan.gui.utils.SwingUtils;
import com.net2plan.gui.utils.topologyPane.visualizationControl.VisualizationState;
import com.net2plan.interfaces.networkDesign.Configuration;
import com.net2plan.interfaces.networkDesign.Net2PlanException;
import com.net2plan.interfaces.networkDesign.NetworkLayer;
import com.net2plan.interfaces.simulation.SimEvent;
import com.net2plan.internal.ErrorHandling;
import com.net2plan.internal.IExternal;
import com.net2plan.internal.SystemUtils;
import com.net2plan.internal.plugins.IGUIModule;
import com.net2plan.internal.sim.EndSimulationException;
import com.net2plan.internal.sim.IGUISimulationListener;
import com.net2plan.internal.sim.SimCore;
import com.net2plan.internal.sim.SimCore.SimState;
import com.net2plan.internal.sim.SimKernel;
import com.net2plan.utils.ClassLoaderUtils;
import com.net2plan.utils.Pair;
import com.net2plan.utils.StringUtils;
import com.net2plan.utils.Triple;

import net.miginfocom.swing.MigLayout;

/**
 * Targeted to evaluate network designs from the offline tool simulating the
 * network operation. Different aspects such as network resilience,
 * connection-admission-control and time-varying traffic resource allocation,
 * or even mix of them, can be analyzed using the online simulator.
 *
 * @author Pablo Pavon-Marino, Jose-Luis Izquierdo-Zaragoza
 * @since 0.3.0
 */
public class OnlineSimulationPane extends JTabbedPane implements ActionListener, IGUISimulationListener {

    private final IVisualizationCallback mainWindow;
    private final int simReportTab;
    private JButton btn_run, btn_step, btn_pause, btn_stop, btn_reset;
    private JButton btn_viewEventList, btn_updateReport;
    private JPanel simReport;
    private JCheckBox chk_refresh;
    private JPanel pan_simulationController;
    private JTextArea simInfo;
    private JToolBar toolbar;
    private JSplitPane splitPaneConfiguration;
    private Thread simThread;
    private ParameterValueDescriptionPanel simulationConfigurationPanel;
    private RunnableSelector eventGeneratorPanel, eventProcessorPanel;
    private SimKernel simKernel;
    private JPanel simulationControlPanel;

    public OnlineSimulationPane(IVisualizationCallback mainWindow) {
        super();
        this.mainWindow = mainWindow;

        simKernel = new SimKernel();
        simKernel.setGUIListener(this);

        File ALGORITHMS_DIRECTORY = new File(
                IGUIModule.CURRENT_DIR + SystemUtils.getDirectorySeparator() + "workspace");
        ALGORITHMS_DIRECTORY = ALGORITHMS_DIRECTORY.isDirectory() ? ALGORITHMS_DIRECTORY : IGUIModule.CURRENT_DIR;

        eventGeneratorPanel = new RunnableSelector(SimKernel.getEventGeneratorLabel(), "File",
                simKernel.getEventGeneratorClass(), ALGORITHMS_DIRECTORY, new ParameterValueDescriptionPanel());
        eventProcessorPanel = new RunnableSelector(SimKernel.getEventProcessorLabel(), "File",
                simKernel.getEventProcessorClass(), ALGORITHMS_DIRECTORY, new ParameterValueDescriptionPanel());

        simulationConfigurationPanel = new ParameterValueDescriptionPanel();
        simulationConfigurationPanel.setParameters(simKernel.getSimulationParameters());

        JTabbedPane configPane = new JTabbedPane();
        configPane.addTab(SimKernel.getEventGeneratorLabel(), eventGeneratorPanel);
        configPane.addTab(SimKernel.getEventProcessorLabel(), eventProcessorPanel);

        JPanel topPane = new JPanel(new MigLayout("insets 0 0 0 0", "[][grow][]", "[][grow]"));
        topPane.add(new JLabel("Simulation parameters"), "spanx 3, wrap");
        topPane.add(simulationConfigurationPanel, "spanx 3, grow, wrap");

        splitPaneConfiguration = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        splitPaneConfiguration.setTopComponent(topPane);
        splitPaneConfiguration.setBottomComponent(configPane);

        splitPaneConfiguration.setResizeWeight(0.5);
        splitPaneConfiguration.addPropertyChangeListener(new ProportionalResizeJSplitPaneListener());
        splitPaneConfiguration
                .setBorder(BorderFactory.createTitledBorder(new LineBorder(Color.BLACK), "Simulation execution"));

        JPanel pan_execution = new JPanel(new MigLayout("fill, insets 0 0 0 0"));
        pan_execution.add(splitPaneConfiguration, "grow");

        btn_updateReport = new JButton("Update");
        btn_updateReport.setToolTipText("Update the simulation report");
        btn_updateReport.addActionListener(this);

        simReport = new JPanel();
        simReport.setLayout(new BorderLayout());
        simReport.add(btn_updateReport, BorderLayout.NORTH);

        addTab("Simulation input parameters", pan_execution);
        simulationControlPanel = configureSimulationControlPanel();
        addTab("Simulation control", simulationControlPanel);
        addTab("Simulation report", simReport);
        simReportTab = 2;

        simKernel.reset();

        if (mainWindow.getDesign() != null)
            simKernel.setNetPlan(mainWindow.getDesign());
    }

    @Override
    public void actionPerformed(final ActionEvent e) {
        try {
            Object src = e.getSource();

            if (src == btn_run) {
                simKernel.setNetPlan(mainWindow.getDesign());
                runSimulation(false);
            } else if (src == btn_step) {
                runSimulation(true);
            } else if (src == btn_pause) {
                simKernel.getSimCore().setSimulationState(
                        simKernel.getSimCore().getSimulationState() == SimState.PAUSED ? SimState.RUNNING
                                : SimState.PAUSED);
            } else if (src == btn_stop) {
                simKernel.getSimCore().setSimulationState(SimState.STOPPED);
            } else if (src == btn_reset) {
                simKernel.getSimCore().setSimulationState(SimState.STOPPED);
                simKernel.reset();
                simKernel.setNetPlan(simKernel.getInitialNetPlan());
                mainWindow.setCurrentNetPlanDoNotUpdateVisualization(simKernel.getInitialNetPlan());
                final VisualizationState vs = mainWindow.getVisualizationState();
                Pair<BidiMap<NetworkLayer, Integer>, Map<NetworkLayer, Boolean>> res = vs
                        .suggestCanvasUpdatedVisualizationLayerInfoForNewDesign(
                                new HashSet<>(mainWindow.getDesign().getNetworkLayers()));
                vs.setCanvasLayerVisibilityAndOrder(mainWindow.getDesign(), res.getFirst(), res.getSecond());
                mainWindow.updateVisualizationAfterNewTopology();
            } else if (src == btn_viewEventList) {
                viewFutureEventList();
            } else if (src == btn_updateReport) {
                updateSimReport();
            } else {
                throw new Net2PlanException("Bad");
            }
        } catch (Net2PlanException ex) {
            if (ErrorHandling.isDebugEnabled())
                ErrorHandling.addErrorOrException(ex, OnlineSimulationPane.class);
            ErrorHandling.showErrorDialog(ex.getMessage(), "Error executing simulation");
        } catch (Throwable ex) {
            ErrorHandling.addErrorOrException(ex, OnlineSimulationPane.class);
            ErrorHandling.showErrorDialog("An error happened");
        }
    }

    private JPanel configureSimulationControlPanel() {
        pan_simulationController = new JPanel(new MigLayout("fill, insets 0 0 0 0"));
        pan_simulationController
                .setBorder(BorderFactory.createTitledBorder(new LineBorder(Color.BLACK), "Simulation controller"));

        simInfo = new JTextArea();
        simInfo.setFont(new JLabel().getFont());
        DefaultCaret caret = (DefaultCaret) simInfo.getCaret();
        caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);

        toolbar = new JToolBar();

        btn_run = new JButton("Run");
        btn_run.addActionListener(this);
        btn_run.setToolTipText("Execute the simulation [CTRL + U]");
        btn_step = new JButton("Step");
        btn_step.addActionListener(this);
        btn_step.setToolTipText("Execute the next scheduled event and pause");
        btn_pause = new JButton("Pause/Continue");
        btn_pause.addActionListener(this);
        btn_pause.setToolTipText("Pause the simulation (if active) or continue (if paused)");
        btn_stop = new JButton("Stop");
        btn_stop.addActionListener(this);
        btn_stop.setToolTipText("Stop the simulation (it cannot be resumed later)");
        btn_reset = new JButton("Reset");
        btn_reset.addActionListener(this);
        btn_reset.setToolTipText(
                "After stopping the simulation, resets the design to the initial simulation design");
        chk_refresh = new JCheckBox("Refresh");
        chk_refresh.setSelected(true);

        btn_viewEventList = new JButton("View FEL");
        btn_viewEventList.setToolTipText("View future event list (FEL)");
        btn_viewEventList.addActionListener(this);

        toolbar.setFloatable(false);
        toolbar.setRollover(true);
        toolbar.add(btn_run);
        toolbar.add(btn_step);
        toolbar.add(btn_pause);
        toolbar.add(btn_stop);
        toolbar.add(btn_reset);
        toolbar.addSeparator();
        toolbar.add(chk_refresh);
        toolbar.add(Box.createHorizontalGlue());
        toolbar.add(btn_viewEventList);

        pan_simulationController.add(toolbar, "dock north");
        pan_simulationController.add(new JScrollPane(simInfo), "grow");

        return pan_simulationController;
    }

    @Override
    public void refresh(boolean forceRefresh) {
        if (chk_refresh.isSelected() || forceRefresh)
            updateSimulationInfo();
    }

    @SuppressWarnings("deprecation")
    @Override
    public void simulationStateChanged(SimCore.SimState simulationState, Throwable reason) {
        simulationConfigurationPanel.setEnabled(false);
        eventGeneratorPanel.setEnabled(false);
        eventProcessorPanel.setEnabled(false);

        switch (simulationState) {
        case NOT_STARTED:
            btn_run.setEnabled(true);
            btn_step.setEnabled(true);
            btn_pause.setEnabled(false);
            btn_stop.setEnabled(false);
            btn_reset.setEnabled(false);

            simulationConfigurationPanel.setEnabled(true);
            eventGeneratorPanel.setEnabled(true);
            eventProcessorPanel.setEnabled(true);

            if (simThread != null) {
                try {
                    simThread.stop();
                } catch (Throwable e) {
                }
            }

            break;

        case RUNNING:
        case STEP:
            btn_run.setEnabled(false);
            btn_step.setEnabled(false);
            btn_pause.setEnabled(true);
            btn_stop.setEnabled(true);
            btn_reset.setEnabled(false);
            break;

        case PAUSED:
            btn_run.setEnabled(false);
            btn_step.setEnabled(true);
            btn_pause.setEnabled(true);
            btn_stop.setEnabled(true);
            btn_reset.setEnabled(false);
            break;

        case STOPPED:
            btn_run.setEnabled(false);
            btn_step.setEnabled(false);
            btn_pause.setEnabled(false);
            btn_stop.setEnabled(false);
            btn_reset.setEnabled(true);
            break;

        default:
            throw new RuntimeException("Bad - Unknown simulation state");
        }

        if (simulationState == SimState.NOT_STARTED || simulationState == SimState.PAUSED
                || simulationState == SimState.STEP || simulationState == SimState.STOPPED) {
            updateSimulationInfo();
            mainWindow.setCurrentNetPlanDoNotUpdateVisualization(simKernel.getCurrentNetPlan());
            final VisualizationState vs = mainWindow.getVisualizationState();
            Pair<BidiMap<NetworkLayer, Integer>, Map<NetworkLayer, Boolean>> res = vs
                    .suggestCanvasUpdatedVisualizationLayerInfoForNewDesign(
                            new HashSet<>(mainWindow.getDesign().getNetworkLayers()));
            vs.setCanvasLayerVisibilityAndOrder(mainWindow.getDesign(), res.getFirst(), res.getSecond());
            mainWindow.updateVisualizationAfterNewTopology();
        }

        if (reason == null)
            return;

        if (reason instanceof EndSimulationException) {
            ErrorHandling.showInformationDialog("Simulation finished", "Information");
            updateSimReport();
            if (getSelectedIndex() != simReportTab)
                setSelectedIndex(simReportTab);
            requestFocusInWindow();
        } else if (reason instanceof Net2PlanException || reason instanceof JOMException) {
            if (ErrorHandling.isDebugEnabled())
                ErrorHandling.addErrorOrException(reason, OnlineSimulationPane.class);
            ErrorHandling.showErrorDialog(reason.getMessage(), "Error executing simulation");
        } else {
            ErrorHandling.addErrorOrException(reason, OnlineSimulationPane.class);
            ErrorHandling.showErrorDialog("Fatal error");
        }
    }

    private void updateSimulationLog(String text) {
        simInfo.setText(null);
        simInfo.setText(text);
        simInfo.setCaretPosition(0);
    }

    public void runSimulation(final boolean stepByStep) {
        try {
            if (simKernel.getSimCore().getSimulationState() == NOT_STARTED) {
                Map<String, String> simulationParameters = simulationConfigurationPanel.getParameters();
                Map<String, String> net2planParameters = Configuration.getNet2PlanOptions();

                Triple<File, String, Class> aux;

                aux = eventGeneratorPanel.getRunnable();
                Map<String, String> eventGeneratorParameters = eventGeneratorPanel.getRunnableParameters();
                IExternal eventGenerator = ClassLoaderUtils.getInstance(aux.getFirst(), aux.getSecond(),
                        simKernel.getEventGeneratorClass());

                aux = eventProcessorPanel.getRunnable();
                IExternal eventProcessor = ClassLoaderUtils.getInstance(aux.getFirst(), aux.getSecond(),
                        simKernel.getEventProcessorClass());
                Map<String, String> eventProcessorParameters = eventProcessorPanel.getRunnableParameters();
                simKernel.configureSimulation(simulationParameters, net2planParameters, eventGenerator,
                        eventGeneratorParameters, eventProcessor, eventProcessorParameters);
                simKernel.initialize();
                simKernel.getSimCore()
                        .setSimulationState(stepByStep ? SimCore.SimState.STEP : SimCore.SimState.RUNNING);

                updateSimulationLog("Simulation running...");

                simThread = new Thread(simKernel.getSimCore());
                simThread.start();
            } else {
                simKernel.getSimCore()
                        .setSimulationState(stepByStep ? SimCore.SimState.STEP : SimCore.SimState.RUNNING);
            }
        } catch (Net2PlanException ex) {
            simKernel.reset();
            if (ErrorHandling.isDebugEnabled())
                ErrorHandling.addErrorOrException(ex, OnlineSimulationPane.class);
            ErrorHandling.showErrorDialog(ex.getMessage(), "Unable to execute simulation");
        } catch (Throwable ex) {
            simKernel.reset();
            ErrorHandling.addErrorOrException(ex, OnlineSimulationPane.class);
            ErrorHandling.showErrorDialog("Error execution simulation");
        }
    }

    private void updateSimulationInfo() {
        if (SwingUtilities.isEventDispatchThread()) {
            updateSimulationLog(simKernel.getSimulationInfo());
        } else {
            try {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        updateSimulationLog(simKernel.getSimulationInfo());
                    }
                });
            } catch (Throwable e) {
                throw new RuntimeException(e);
            }
        }
    }

    private void updateSimReport() {
        try {
            if (simKernel.getSimCore().getSimulationState() == SimCore.SimState.NOT_STARTED) {
                throw new Net2PlanException("Simulation not started yet");
            }

            JPanel pane = new ReportBrowser(simKernel.getSimulationReport());
            try {
                simReport.remove(((BorderLayout) simReport.getLayout()).getLayoutComponent(BorderLayout.CENTER));
            } catch (Throwable ex) {
            }

            simReport.add(pane, BorderLayout.CENTER);
            simReport.revalidate();
        } catch (Net2PlanException ex) {
            if (ErrorHandling.isDebugEnabled())
                ErrorHandling.addErrorOrException(ex, OnlineSimulationPane.class);
            ErrorHandling.showErrorDialog(ex.getMessage(), "Unable to show simulation report");
        } catch (Throwable ex) {
            ErrorHandling.addErrorOrException(ex, OnlineSimulationPane.class);
            ErrorHandling.showErrorDialog("Error updating simulation report");
        }
    }

    /**
     * Shows the future event list.
     *
     * @since 0.3.0
     */
    public void viewFutureEventList() {
        final JDialog dialog = new JDialog();
        dialog.setTitle("Future event list");
        SwingUtils.configureCloseDialogOnEscape(dialog);
        dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
        dialog.setSize(new Dimension(500, 300));
        dialog.setLocationRelativeTo(null);
        dialog.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
        dialog.setLayout(new MigLayout("fill, insets 0 0 0 0"));

        final String[] tableHeader = StringUtils.arrayOf("Id", "Time", "Priority", "Type", "To module",
                "Custom object");
        Object[][] data = new Object[1][tableHeader.length];

        DefaultTableModel model = new ClassAwareTableModel();
        model.setDataVector(new Object[1][tableHeader.length], tableHeader);

        JTable table = new AdvancedJTable(model);
        RowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
        table.setRowSorter(sorter);
        JScrollPane scrollPane = new JScrollPane(table);
        dialog.add(scrollPane, "grow");

        PriorityQueue<SimEvent> futureEventList = simKernel.getSimCore().getFutureEventList().getPendingEvents();
        if (!futureEventList.isEmpty()) {
            int numEvents = futureEventList.size();
            SimEvent[] futureEventList_array = futureEventList.toArray(new SimEvent[numEvents]);
            Arrays.sort(futureEventList_array, futureEventList.comparator());
            data = new Object[numEvents][tableHeader.length];

            for (int eventId = 0; eventId < numEvents; eventId++) {
                //            List<SimAction> actions = futureEventList_array[eventId].getEventActionList();
                Object customObject = futureEventList_array[eventId].getEventObject();
                data[eventId][0] = eventId;
                data[eventId][1] = StringUtils
                        .secondsToYearsDaysHoursMinutesSeconds(futureEventList_array[eventId].getEventTime());
                data[eventId][2] = futureEventList_array[eventId].getEventPriority();
                data[eventId][3] = futureEventList_array[eventId].getEventType();
                data[eventId][4] = futureEventList_array[eventId].getEventDestinationModule().toString();
                data[eventId][5] = customObject == null ? "none" : customObject;
            }
        }

        model.setDataVector(data, tableHeader);
        table.getTableHeader().addMouseListener(new ColumnFitAdapter());
        table.setDefaultRenderer(Double.class, new CellRenderers.NumberCellRenderer());

        dialog.setVisible(true);
    }

    public SimKernel getSimKernel() {
        return simKernel;
    }

    public boolean isRunButtonEnabled() {
        return btn_run.isEnabled();
    }
}