Commit 35ea93a4 authored by Simon Luser's avatar Simon Luser
Browse files

Merge remote-tracking branch 'origin/master' into pl/disasterPrioritization

parents 92774550 6c429d62
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.views.fiveg.utils;
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import de.tud.kom.p2psim.impl.topology.views.FiveGTopologyView;
import de.tud.kom.p2psim.impl.topology.views.fiveg.ModelBasedSegmentDatabase;
import de.tud.kom.p2psim.impl.topology.views.fiveg.models.AbstractModel;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Oracle;
/**
* A simple graph for debugging the models of the
* {@link ModelBasedSegmentDatabase} used by the {@link FiveGTopologyView}.
*
* @author Marc Schiller
* @version 1.0, 15 Dec 2016
*/
public class Graph extends JFrame implements EventHandler {
AbstractModel model = null;
public Graph() {
super("FiveGTopology - Cell Model Debug Graph");
Event.scheduleImmediately(this, null, 0);
}
public void setModel(AbstractModel model) {
this.model = model;
}
@Override
public void eventOccurred(Object content, int type) {
if (model.getDebug()) {
XYSeries data = new XYSeries("ModelData");
for (int i = 0; i < Oracle.getAllHosts().size(); i += 1) {
data.add(i, model.getDouble(i));
}
JFreeChart xyChart = ChartFactory.createXYLineChart(
model.getParameterType().toString() + " -- " + model.toString(), "Users", "Value",
new XYSeriesCollection(data), PlotOrientation.VERTICAL,
false, true, false);
// X-Axis Ticks every 5%
((NumberAxis) xyChart.getXYPlot().getDomainAxis())
.setTickUnit(new NumberTickUnit(Oracle.getAllHosts().size() / 20));
ChartPanel chartPanel = new ChartPanel(xyChart);
setContentPane(chartPanel);
pack();
setVisible(true);
}
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.views.fiveg.utils;
/**
* Enumeration for defining the type (Bandwidth, Drop Rate, Latency) for a model.
* @author Marc Schiller
* @version 1.0, 15 Dec 2016
*/
public enum ParameterType {
BANDWIDTH(),
DROPRATE(),
LATENCY();
public static String printTypes() {
ParameterType[] types = values();
String out = "";
for (int i = 0; i < types.length; i++) {
if (i > 0) {
out += ", ";
}
out += types[i].name();
}
return out;
}
}
package de.tud.kom.p2psim.impl.topology.views.visualization.ui;
import de.tudarmstadt.maki.simonstrator.api.NodeDebugMonitor;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Vector;
/**
* The actual frame/view displaying the node data. Simply a frame that holds a table
* displaying the info.
*/
public class DebugNodeView extends JFrame
{
private JPanel panel;
private JTable table;
private DefaultTableModel model;
private long hostId;
public DebugNodeView(long hostId)
{
this.hostId = hostId;
setTitle("Host: " + hostId);
SwingUtilities.invokeLater(this::createGUI);
}
/**
* Initialise the UI
*/
private void createGUI()
{
panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.setPreferredSize(new Dimension(300,300));
Map<Class, HashMap<String, Object>> nodeData = NodeDebugMonitor.getNodeData(INodeID.get(hostId));
Vector tableData = convertToTableVector(nodeData);
Vector<String> columns = new Vector<>();
columns.add("Klasse");
columns.add("Beschreibung");
columns.add("Wert");
model = new DefaultTableModel(tableData, columns);
table = new JTable(model);
JScrollPane scrollPane = new JScrollPane(table);
table.setFillsViewportHeight(true);
panel.add(scrollPane, BorderLayout.NORTH);
getContentPane().add(panel);
pack();
setVisible(true);
}
/**
* Updates an entry for a node
* @param subject The class which provided the info
* @param entry the entry/key
* @param value the value
*/
public void update(Class subject, String entry, String value)
{
int rowIndex = findEntry(subject.getSimpleName(), entry);
//If the entry already existed it needs to be updates.
if(rowIndex >= 0)
{
//2 is the position of the value in the vector.
((Vector) model.getDataVector().get(rowIndex)).set(2, value);
model.fireTableDataChanged();
}
//If the entry didn't exist, a new row is inserted.
else
{
String[] data = {subject.getSimpleName(), entry, value};
model.addRow(data);
}
}
/**
* Finds the row in the data vector which holds the specified entry
* @param subject the providing class
* @param entry the entry
* @return the index of the row holding the entry
*/
private int findEntry(String subject, String entry)
{
Vector data = model.getDataVector();
for(int i = 0; i < data.size(); i++)
{
Vector v = (Vector) data.get(i);
if(v.get(0).equals(subject) && v.get(1).equals(entry))
{
return i;
}
}
return -1;
}
/**
* Converts a hashmap with the per node information as provided by the {@link NodeDebugMonitor}
* to a data vector which can be used in a table model.
* @param nodeData the data which should be converted.
* @return a vector holding all the data which can be used for table models.
*/
private Vector<Vector<String>> convertToTableVector(Map<Class, HashMap<String, Object>> nodeData)
{
Vector<Vector<String>> tableData = new Vector<>();
for (Map.Entry<Class, HashMap<String, Object>> classData : nodeData.entrySet())
{
String classname = classData.getKey().getSimpleName();
for(Map.Entry<String, Object> entry : classData.getValue().entrySet())
{
String value;
if (entry.getValue() == null) value = "NULL";
else value = entry.getValue().toString();
Vector<String> entryVector = new Vector<>();
entryVector.add(classname);
entryVector.add(entry.getKey());
entryVector.add(value);
tableData.add(entryVector);
}
}
return tableData;
}
}
package de.tud.kom.p2psim.impl.topology.views.visualization.ui;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView;
import de.tud.kom.p2psim.impl.topology.views.visualization.world.NodeVisInteractionListener;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.NodeDebugMonitor;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import de.tudarmstadt.maki.simonstrator.api.component.core.NodeDebugMonitorComponent;
import java.util.HashMap;
/**
* Managing class for the presentation of the per node data. All the little "per-node-frames" are handled here.
*/
public class NodeDebugVisualisation implements NodeVisInteractionListener, NodeDebugMonitorComponent.NodeDebugUpdateListener
{
/**
* The info frames that currently exist.
*/
private HashMap<Long, DebugNodeView> frames = new HashMap<>();
public NodeDebugVisualisation()
{
Event.scheduleImmediately((content, type) -> {
NodeDebugMonitor.addUpdateListener(NodeDebugVisualisation.this);
VisualizationTopologyView.VisualizationInjector.addInteractionListener(NodeDebugVisualisation.this);
}, null, 0);
}
@Override
public void onHostClick(long hostID, boolean isActive)
{
if(isActive)
{
frames.put(hostID, new DebugNodeView(hostID));
}
else
{
DebugNodeView view = frames.remove(hostID);
view.dispose();
}
}
@Override
public void onNodeDebugUpdate(Class subject, INodeID nodeId, String entry, Object value)
{
String string;
if(value == null) string = "NULL";
else string = value.toString();
if(frames.containsKey(nodeId.value()))
{
frames.get(nodeId.value()).update(subject, entry, string);
}
}
}
...@@ -20,44 +20,40 @@ ...@@ -20,44 +20,40 @@
package de.tud.kom.p2psim.impl.topology.views.visualization.ui; package de.tud.kom.p2psim.impl.topology.views.visualization.ui;
import java.awt.BorderLayout; import java.awt.*;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.util.Map; import java.util.Map;
import javax.swing.BorderFactory; import javax.swing.*;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder; import javax.swing.border.BevelBorder;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
/**
* JFrame which holds all the live plots.
*
* @author Unknown
*
* 21.03.2017 Clemens Krug:
* Changed this class up quite a bit because when one would
* add more and more metrics to the visualisation, they would get unreadable small. Reworked this
* class so the charts will allways fill the view if theres is space, but if you add do many plots
* they will stay add a minimum height of 250 px and a scrollbar will be added instead.
*/
public class PlottingView extends JFrame { public class PlottingView extends JFrame {
private static final int VIEW_WIDTH = 900; private static final int VIEW_WIDTH = 900;
private static final int VIEW_HEIGHT = 800; private static final int VIEW_HEIGHT = 800;
private static final int PLOT_HEIGHT = 120;
private static final int PLOT_HEIGHT_MIN = 250;
private static final Color PLOT_BACKGROUND_COLOR = Color.WHITE; private static final Color PLOT_BACKGROUND_COLOR = Color.WHITE;
private String name;
private Map<String, XYChart> nameToPlotMap = Maps.newLinkedHashMap(); private Map<String, XYChart> nameToPlotMap = Maps.newLinkedHashMap();
private JPanel content; private JPanel plotBox;
private JPanel selectorPanel; private JScrollPane spane;
private Box plotBox;
private GridBagConstraints layoutConstraints;
public PlottingView(String name) { public PlottingView(String name) {
this.name = name;
setTitle(name); setTitle(name);
setVisible(true); setVisible(true);
...@@ -65,26 +61,16 @@ public class PlottingView extends JFrame { ...@@ -65,26 +61,16 @@ public class PlottingView extends JFrame {
} }
private void buildUI() { private void buildUI() {
content = new JPanel(); plotBox = new PlotBox();
content.setLayout(new BorderLayout()); plotBox.setLayout(new BoxLayout(plotBox, BoxLayout.Y_AXIS));
selectorPanel = new JPanel();
selectorPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
layoutConstraints = new GridBagConstraints();
layoutConstraints.anchor = GridBagConstraints.NORTH;
layoutConstraints.weighty = 1;
plotBox = Box.createVerticalBox();
plotBox.setBackground(PLOT_BACKGROUND_COLOR); plotBox.setBackground(PLOT_BACKGROUND_COLOR);
plotBox.setBorder(BorderFactory.createEtchedBorder()); plotBox.setBorder(BorderFactory.createEtchedBorder());
content.add(selectorPanel, BorderLayout.NORTH); spane = new JScrollPane(plotBox);
content.add(plotBox, BorderLayout.CENTER); add(spane);
add(content, BorderLayout.CENTER);
setSize(VIEW_WIDTH, VIEW_HEIGHT); setSize(VIEW_WIDTH, VIEW_HEIGHT);
setPreferredSize(new Dimension(VIEW_WIDTH, VIEW_HEIGHT));
} }
public XYChart createPlot(String name, String seriesName) { public XYChart createPlot(String name, String seriesName) {
...@@ -95,7 +81,8 @@ public class PlottingView extends JFrame { ...@@ -95,7 +81,8 @@ public class PlottingView extends JFrame {
chartPanel = wrapInCollabsable(chartPanel, name); chartPanel = wrapInCollabsable(chartPanel, name);
plotBox.add(chartPanel); plotBox.add(chartPanel);
plotBox.validate(); plotBox.repaint();
spane.validate();
nameToPlotMap.put(name, plot); nameToPlotMap.put(name, plot);
...@@ -140,9 +127,12 @@ public class PlottingView extends JFrame { ...@@ -140,9 +127,12 @@ public class PlottingView extends JFrame {
if (collapseButton.getText().equals("-")) { if (collapseButton.getText().equals("-")) {
collapseButton.setText("+"); collapseButton.setText("+");
panel.remove(innerPanel); panel.remove(innerPanel);
panel.setMinimumSize(header.getPreferredSize());
panel.repaint();
} else { } else {
collapseButton.setText("-"); collapseButton.setText("-");
panel.add(innerPanel, BorderLayout.CENTER); panel.add(innerPanel, BorderLayout.CENTER);
panel.setMinimumSize(new Dimension(850,PLOT_HEIGHT_MIN));
} }
} }
}); });
...@@ -158,6 +148,7 @@ public class PlottingView extends JFrame { ...@@ -158,6 +148,7 @@ public class PlottingView extends JFrame {
panel.add(header, BorderLayout.NORTH); panel.add(header, BorderLayout.NORTH);
panel.add(innerPanel, BorderLayout.CENTER); panel.add(innerPanel, BorderLayout.CENTER);
panel.setMinimumSize(new Dimension(850,PLOT_HEIGHT_MIN));
return panel; return panel;
} }
...@@ -165,7 +156,67 @@ public class PlottingView extends JFrame { ...@@ -165,7 +156,67 @@ public class PlottingView extends JFrame {
public void removeAllPlots() { public void removeAllPlots() {
nameToPlotMap.clear(); nameToPlotMap.clear();
plotBox.removeAll(); plotBox.removeAll();
content.doLayout(); plotBox.validate();
content.validate(); }
/**
* Custom JPanel to implement the desired scrolling policy. Basically
* there won't be a scrollbar if all of the components have a greater height than
* {@link #PLOT_HEIGHT_MIN}. However, if you add so many components that they can't
* fit in while maintaining that minimum height, a scrollbar will be added.
*
* @author Clemens Krug
*/
private class PlotBox extends JPanel implements Scrollable
{
private boolean enableScroll = false;
private Dimension preferredSize = new Dimension(VIEW_WIDTH, 800);
@Override
public Component add(Component comp)
{
Component retComp = super.add(comp);
preferredSize.height = getComponentCount() * PLOT_HEIGHT_MIN;
checkScrollNeeded();
return retComp;
}
/**
* Check if scrolling should be enabled and to so if it should.
*/
private void checkScrollNeeded()
{
enableScroll = getComponentCount() * PLOT_HEIGHT_MIN > getParent().getHeight();
}
@Override
public Dimension getPreferredSize() {
return preferredSize;
}
@Override
public Dimension getPreferredScrollableViewportSize() {
return getPreferredSize();
}
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return 50;
}
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return PLOT_HEIGHT_MIN;
}
@Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
@Override
public boolean getScrollableTracksViewportHeight() {
return !enableScroll;
}
} }
} }
\ No newline at end of file
...@@ -20,38 +20,54 @@ ...@@ -20,38 +20,54 @@
package de.tud.kom.p2psim.impl.topology.views.visualization.world; package de.tud.kom.p2psim.impl.topology.views.visualization.world;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.impl.topology.views.FiveGTopologyView; import de.tud.kom.p2psim.impl.topology.views.FiveGTopologyView;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector; import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.views.fiveg.AbstractGridBasedTopologyDatabase; import de.tud.kom.p2psim.impl.topology.views.fiveg.AbstractGridBasedTopologyDatabase;
import de.tud.kom.p2psim.impl.topology.views.fiveg.FiveGTopologyDatabase.Entry; import de.tud.kom.p2psim.impl.topology.views.fiveg.FiveGTopologyDatabase.Entry;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Rate; import de.tudarmstadt.maki.simonstrator.api.Rate;
import de.tudarmstadt.maki.simonstrator.api.Time; import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
/** /**
* Visualization for the {@link FiveGTopologyView} * Visualization for the {@link FiveGTopologyView}
* *
* Added 06.10.2016 Nils Richerzhagen, Clemens Krug * Added 06.10.2016 Nils Richerzhagen, Clemens Krug Functionality to 'destroy'
* Functionality to 'destroy' cells using SHIFT + Left-click. Enable/Disable using the enableCellDestruction * cells using SHIFT + Left-click. Enable/Disable using the
* enableCellDestruction
*
* Update 04.07.2017 Nils Richerzhagen Visualization to work with
* VisualizationInjector.scaleValue(...); stroke width of broken cells reduced
* for "nicer" visuals
* *
* @author Bjoern Richerzhagen * @author Bjoern Richerzhagen
* @version 1.0, Nov 5, 2015 * @version 1.0, Nov 5, 2015
*/ */
public class FiveGVisualization extends JComponent implements VisualizationInjector.MouseClickListener { public class FiveGVisualization extends JComponent
implements VisualizationInjector.MouseClickListener {
private final boolean enableCellDestruction; private final boolean enableCellDestruction;
protected BufferedImage image; protected BufferedImage image;
protected volatile boolean needsRedraw = true; protected volatile boolean needsRedraw = true;
private final AbstractGridBasedTopologyDatabase database; private final AbstractGridBasedTopologyDatabase database;
public FiveGVisualization(AbstractGridBasedTopologyDatabase database, boolean enableCellDestruction) { public FiveGVisualization(AbstractGridBasedTopologyDatabase database,
boolean enableCellDestruction) {
setBounds(0, 0, VisualizationInjector.getWorldX(), setBounds(0, 0, VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY()); VisualizationInjector.getWorldY());
setOpaque(true); setOpaque(true);
...@@ -62,7 +78,7 @@ public class FiveGVisualization extends JComponent implements VisualizationInjec ...@@ -62,7 +78,7 @@ public class FiveGVisualization extends JComponent implements VisualizationInjec
VisualizationInjector.getWorldY(), BufferedImage.TYPE_INT_ARGB); VisualizationInjector.getWorldY(), BufferedImage.TYPE_INT_ARGB);
this.enableCellDestruction = enableCellDestruction; this.enableCellDestruction = enableCellDestruction;
VisualizationInjector.addMouseListener(this); VisualizationInjector.addMouseListener(this);
} }
...@@ -108,70 +124,90 @@ public class FiveGVisualization extends JComponent implements VisualizationInjec ...@@ -108,70 +124,90 @@ public class FiveGVisualization extends JComponent implements VisualizationInjec
double minLatency = Double.MAX_VALUE; double minLatency = Double.MAX_VALUE;
boolean isUpload = false; boolean isUpload = false;
for (int x = 0; x < VisualizationInjector.getWorldX(); x += stepSize) { try {
for (int y = 0; y < VisualizationInjector for (int x = 0; x < Binder.getComponent(Topology.class)
.getWorldY(); y += stepSize) { .getWorldDimensions().getX(); x += stepSize) {
// TODO add checkbox for cloudlets? for (int y = 0; y < Binder.getComponent(Topology.class)
Entry entry = database.getEntryFor(database.getSegmentID(x, y), .getWorldDimensions().getY(); y += stepSize) {
false); // TODO add checkbox for cloudlets?
if (entry == null) { Entry entry = database
continue; .getEntryFor(database.getSegmentID(x, y), false);
if (entry == null) {
continue;
}
} }
} }
}
for (int x = 0; x < VisualizationInjector.getWorldX(); x += stepSize) { for (int x = 0; x < Binder.getComponent(Topology.class)
for (int y = 0; y < VisualizationInjector .getWorldDimensions().getX(); x += stepSize) {
.getWorldY(); y += stepSize) { for (int y = 0; y < Binder.getComponent(Topology.class)
.getWorldDimensions().getY(); y += stepSize) {
// TODO add checkbox for cloudlets?
Entry entry = database.getEntryFor(database.getSegmentID(x, y), // TODO add checkbox for cloudlets?
false); Entry entry = database
if (entry == null) { .getEntryFor(database.getSegmentID(x, y), false);
continue; if (entry == null) {
} continue;
}
// TODO add checkbox for upload/download toggle?
// TODO add checkbox for upload/download toggle?
// Latency
double latencyFactor = (entry.getLatency(isUpload) - minLatency) // Latency
/ (maxLatency - minLatency); double latencyFactor = (entry.getLatency(isUpload)
g2.setColor( - minLatency) / (maxLatency - minLatency);
new Color(255, 0, 0, 10 + (int) (40 * latencyFactor))); g2.setColor(new Color(255, 0, 0,
g2.fillRect(x, y, stepSize, stepSize); 10 + (int) (40 * latencyFactor)));
g2.fillRect(VisualizationInjector.scaleValue(x),
// Drop-Prob VisualizationInjector.scaleValue(y),
g2.setColor(new Color(255, 0, 0, VisualizationInjector.scaleValue(stepSize),
10 + (int) (100 * entry.getDropProbability(isUpload)))); VisualizationInjector.scaleValue(stepSize));
float strokeWidth = (float) entry.getDropProbability(isUpload);
g2.setStroke(new BasicStroke((10 * strokeWidth))); // Drop-Prob
g2.drawRect(x, y, stepSize, stepSize); g2.setColor(new Color(255, 0, 0, 10 + (int) (100
g2.setColor(new Color(255, 255, 255, 255)); * entry.getDropProbability(isUpload))));
g2.drawString("L: " float strokeWidth = (float) entry
+ entry.getLatency(isUpload) / Time.MILLISECOND + " ms", .getDropProbability(isUpload);
x + 10, y + 15); g2.setStroke(new BasicStroke((5 * strokeWidth)));
g2.drawString( g2.drawRect(VisualizationInjector.scaleValue(x),
"D: " + (int) (entry.getDropProbability(isUpload) * 100) VisualizationInjector.scaleValue(y),
+ " %", VisualizationInjector.scaleValue(stepSize),
x + 10, y + 25); VisualizationInjector.scaleValue(stepSize));
g2.drawString("BW: " g2.setColor(new Color(255, 255, 255, 255));
+ (int) (entry.getBandwidth(isUpload) / Rate.kbit_s) g2.drawString("L: "
+ " kBit/s", x + 10, y + 35); + entry.getLatency(isUpload) / Time.MILLISECOND
if(!entry.isAvailable()) { + " ms", VisualizationInjector.scaleValue(x + 10),
g2.drawString("!DEAD!", x + 30, y + 70); VisualizationInjector.scaleValue(y + 15));
g2.drawString("D: "
+ (int) (entry.getDropProbability(isUpload) * 100)
+ " %", VisualizationInjector.scaleValue(x + 10),
VisualizationInjector.scaleValue(y + 35));
g2.drawString("BW: "
+ (int) (entry.getBandwidth(isUpload) / Rate.kbit_s)
+ " kBit/s",
VisualizationInjector.scaleValue(x + 10),
VisualizationInjector.scaleValue(y + 55));
if (!entry.isAvailable()) {
g2.drawString("!DEAD!",
VisualizationInjector.scaleValue(x + 30),
VisualizationInjector.scaleValue(y + 70));
}
} }
} }
} catch (ComponentNotAvailableException e) {
throw new AssertionError(
"The Topology should be Binded in the TopologyFactory.");
} }
} }
@Override @Override
public void mouseClicked(int x, int y, int modifier) public void mouseClicked(int x, int y, int modifier) {
{
// 17 == Shift // 17 == Shift
if(enableCellDestruction && modifier == 17) if (enableCellDestruction && modifier == 17) {
{ int segID = database.getSegmentID(
int segID = database.getSegmentID(x, y); VisualizationInjector.originalValue(x),
VisualizationInjector.originalValue(y));
Entry entry = database.getEntryFor(segID, false); Entry entry = database.getEntryFor(segID, false);
entry.setAvailability(!entry.isAvailable()); entry.setAvailability(!entry.isAvailable());
needsRedraw = true; needsRedraw = true;
......
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.views.visualization.world;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.HashSet;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JMenu;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.impl.topology.views.FiveGTopologyView;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector.MouseClickListener;
import de.tud.kom.p2psim.impl.topology.views.fiveg.FiveGTopologyDatabase.Entry;
import de.tud.kom.p2psim.impl.topology.views.fiveg.ModelBasedSegmentDatabase;
import de.tud.kom.p2psim.impl.topology.views.fiveg.ModelBasedSegmentDatabase.ModelBasedEntry;
import de.tud.kom.p2psim.impl.topology.views.fiveg.utils.Direction;
import de.tud.kom.p2psim.impl.topology.views.fiveg.utils.ParameterType;
import de.tud.kom.p2psim.impl.topology.views.visualization.ui.VisualizationComponent;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
/**
* Visualization for the {@link FiveGTopologyView} using the
* {@link ModelBasedSegmentDatabase}.
*
* @author Marc Schiller, Nils Richerzhagen
* @version 1.0, Jul 7, 2017
*/
public class ModelFiveGVisualization extends JComponent
implements VisualizationComponent, ActionListener, MouseClickListener {
private static final ModelFiveGVisualization instance = new ModelFiveGVisualization();
private ModelBasedSegmentDatabase database;
private final JMenu menu = new JMenu("FiveG");
protected BufferedImage image;
protected volatile boolean needsRedraw = false;
private Direction selectedDirection = null;
private ParameterType selectedType = null;
private HashSet<JCheckBoxMenuItem> menuItems = new HashSet<>(6);
private Boolean showText = true;
private ModelFiveGVisualization() {
setBounds(0, 0, VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY());
setOpaque(true);
setVisible(true);
image = new BufferedImage(VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY(), BufferedImage.TYPE_INT_ARGB);
this.generateMenu();
VisualizationInjector.addMouseListener(this);
}
public static ModelFiveGVisualization getInstance() {
return instance;
}
public void setDatabase(ModelBasedSegmentDatabase database) {
this.database = database;
}
@Override
public String getDisplayName() {
return "FiveG";
}
@Override
public JComponent getComponent() {
return this;
}
@Override
public JMenu getCustomMenu() {
return menu;
}
@Override
public boolean isHidden() {
return false;
}
private void generateMenu() {
String[] entries1 = { "Bandwidth", "Latency", "Droprate" };
String[] entries2 = { "Download", "Upload" };
for (String entry1 : entries1) {
JMenu tmpMenu = new JMenu(entry1);
for (String entry2 : entries2) {
JCheckBoxMenuItem checkbox = new JCheckBoxMenuItem(entry2);
checkbox.setName(entry1 + " " + entry2);
checkbox.addActionListener(this);
tmpMenu.add(checkbox);
menuItems.add(checkbox);
}
menu.add(tmpMenu);
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (needsRedraw) {
redraw();
}
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(image, 0, 0, null);
}
protected void redraw() {
needsRedraw = false;
Graphics2D g2 = (Graphics2D) image.getGraphics();
Composite c = g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
Rectangle2D.Double rect = new Rectangle2D.Double(0, 0,
VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY());
g2.fill(rect);
g2.setComposite(c);
try {
drawEntries(g2);
} catch (RuntimeException e) {
e.printStackTrace();
System.exit(0);
needsRedraw = true;
} finally {
// Schedule next redraw
new Thread(() -> {
try {
Thread.sleep(100);
needsRedraw = true;
} catch (InterruptedException e) {
// Ignore any error in Timer
}
}).start();
}
}
private void drawEntries(Graphics2D g2) {
// Iterate over grid coordinates
int stepSize = database.getGridSize();
boolean isUpload = selectedDirection.equals(Direction.UPLOAD) ? true
: false;
try {
// Loop through world
for (int x = 0; x < Binder.getComponent(Topology.class)
.getWorldDimensions().getX(); x += stepSize) {
for (int y = 0; y < Binder.getComponent(Topology.class)
.getWorldDimensions().getY(); y += stepSize) {
// Fetch entry
ModelBasedEntry entry = (ModelBasedEntry) database
.getEntryFor(database.getSegmentID(x, y), false);
// Skip cell if no entry is found
if (entry == null) {
continue;
}
int status = entry.getStatus(selectedType,
selectedDirection);
Color color = null;
if (entry.isAvailable() && status == 0) {
// Cell is ok => green
color = new Color(0, 128, 0, 40);
} else if (entry.isAvailable() && status == 1) {
// Cell is shortly before overload
color = new Color(255, 255, 0, 40);
} else if (!entry.isAvailable() || status == 2) {
// Cell is overloaded or unavailable
color = new Color(255, 0, 0, 100);
}
// Fill with color for given metric
g2.setColor(color);
g2.fillRect(VisualizationInjector.scaleValue(x),
VisualizationInjector.scaleValue(y),
VisualizationInjector.scaleValue(stepSize),
VisualizationInjector.scaleValue(stepSize));
// Draw border
// TODO: Draw red border if segment is overload if
// (entry.isAvailable() && !entry.isOverloaded()) {
if (entry.isAvailable()) {
g2.setColor(new Color(255, 0, 0, 10));
g2.setStroke(new BasicStroke(1));
} else {
g2.setColor(new Color(255, 0, 0, 100));
g2.setStroke(new BasicStroke(5));
}
g2.drawRect(VisualizationInjector.scaleValue(x),
VisualizationInjector.scaleValue(y),
VisualizationInjector.scaleValue(stepSize),
VisualizationInjector.scaleValue(stepSize));
// Write current values to cell
// Set text color for yellow to grey else to white
if (status == 1) {
g2.setColor(new Color(160, 160, 160, 255));
} else {
g2.setColor(new Color(255, 255, 255, 255));
}
if (showText) {
// Latency
if (entry.isAvailable() && !entry.isOverloaded()) {
g2.drawString(
"L: " + entry.getLatency(isUpload) + " ms",
VisualizationInjector.scaleValue(x + 10),
VisualizationInjector.scaleValue(y + 15));
} else {
g2.drawString("L: ∞ ms",
VisualizationInjector.scaleValue(x + 10),
VisualizationInjector.scaleValue(y + 15));
}
// Droprate
g2.drawString(
"D: " + (int) (entry
.getDropProbability(isUpload) * 100)
+ " %",
VisualizationInjector.scaleValue(x + 10),
VisualizationInjector.scaleValue(y + 35));
// Bandwidth
g2.drawString("B: " + entry.getBandwidth(isUpload)
+ " kBit/s",
VisualizationInjector.scaleValue(x + 10),
VisualizationInjector.scaleValue(y + 55));
// SegmentID
g2.drawString("S:" + entry.getSegmentID(),
VisualizationInjector.scaleValue(x + 10),
VisualizationInjector.scaleValue(y + 75));
// Current Hosts in Segment
g2.drawString("H:" + entry.getHostsInSegment(),
VisualizationInjector.scaleValue(x + 10),
VisualizationInjector.scaleValue(y + 95));
}
// Segment is overloaded
if (entry.isOverloaded()) {
g2.drawString("OVERLOAD",
VisualizationInjector.scaleValue(x + 20),
VisualizationInjector.scaleValue(y + 80));
}
// Host has been killed manually
if (!entry.isAvailable()) {
g2.drawString("!DEAD!",
VisualizationInjector.scaleValue(x + 30),
VisualizationInjector.scaleValue(y + 70));
}
}
}
} catch (ComponentNotAvailableException e) {
throw new AssertionError(
"The Topology should be Binded in the TopologyFactory.");
}
}
@Override
public void actionPerformed(ActionEvent e) {
JCheckBoxMenuItem source = (JCheckBoxMenuItem) e.getSource();
String sourceName = source.getName();
switch (sourceName) {
case "Bandwidth Upload":
selectedDirection = Direction.UPLOAD;
selectedType = ParameterType.BANDWIDTH;
break;
case "Bandwidth Download":
selectedDirection = Direction.DOWNLOAD;
selectedType = ParameterType.BANDWIDTH;
break;
case "Latency Upload":
selectedDirection = Direction.UPLOAD;
selectedType = ParameterType.LATENCY;
break;
case "Latency Download":
selectedDirection = Direction.DOWNLOAD;
selectedType = ParameterType.LATENCY;
break;
case "Droprate Upload":
selectedDirection = Direction.UPLOAD;
selectedType = ParameterType.DROPRATE;
break;
case "Droprate Download":
selectedDirection = Direction.DOWNLOAD;
selectedType = ParameterType.DROPRATE;
break;
default:
break;
}
needsRedraw = true;
for (JCheckBoxMenuItem item : menuItems) {
item.setSelected(false);
}
source.setSelected(true);
}
@Override
public void mouseClicked(int x, int y, int modifier) {
// 17 == Shift
if (modifier == 17) {
int segID = database.getSegmentID(
VisualizationInjector.originalValue(x),
VisualizationInjector.originalValue(y));
Entry entry = database.getEntryFor(segID, false);
entry.setAvailability(!entry.isAvailable());
needsRedraw = true;
}
// 18 == STRG || CMD
if (modifier == 18) {
showText = !showText;
needsRedraw = true;
}
}
}
...@@ -263,7 +263,7 @@ public class NodeInfoComponentVis extends JComponent ...@@ -263,7 +263,7 @@ public class NodeInfoComponentVis extends JComponent
// Draw active (green) over underlay vis. // Draw active (green) over underlay vis.
g2.setColor(nodeInfo.isActive() ? activeGreen : Color.LIGHT_GRAY); g2.setColor(nodeInfo.isActive() ? activeGreen : Color.LIGHT_GRAY);
int radius = 3; int radius = 3;
g2.drawOval(center.x - radius, center.y - radius, radius * 2, g2.drawOval(VisualizationInjector.scaleValue(center.x) - radius, VisualizationInjector.scaleValue(center.y) - radius, radius * 2,
radius * 2); radius * 2);
if (!nodeInfo.isActive()) { if (!nodeInfo.isActive()) {
...@@ -285,7 +285,7 @@ public class NodeInfoComponentVis extends JComponent ...@@ -285,7 +285,7 @@ public class NodeInfoComponentVis extends JComponent
continue; continue;
} }
g2.setColor(colors[dim][value]); g2.setColor(colors[dim][value]);
g2.drawArc(center.x-arcSize, center.y-arcSize, 2*arcSize, 2*arcSize, dim*segmentDegrees, segmentDegrees); g2.drawArc(VisualizationInjector.scaleValue(center.x)-arcSize, VisualizationInjector.scaleValue(center.y)-arcSize, 2*arcSize, 2*arcSize, dim*segmentDegrees, segmentDegrees);
} }
g2.setStroke(new BasicStroke(1)); g2.setStroke(new BasicStroke(1));
......
package de.tud.kom.p2psim.impl.util;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
/**
* Reader for csv files. To use this reader you need to implement the
* {@link #parse(String[])}.
*
* @author Clemens Krug
*/
public abstract class CSVReader<T>
{
private String filename;
private String SEP;
public CSVReader(String filename, String SEP)
{
this.filename = filename;
this.SEP = SEP;
}
/**
* Reads the data into a list.
* @return A list of the generated objects.
*/
public List<T> readData()
{
List<T> data = new LinkedList<>();
BufferedReader csv = null;
try {
csv = new BufferedReader(new FileReader(filename));
while (csv.ready()) {
String line = csv.readLine();
if (line.contains(SEP)) {
String[] parts = line.split(SEP);
T entry = parse(parts);
if(entry != null) data.add(entry);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (csv != null) {
try {
csv.close();
} catch (IOException e) {
//nothing
}
}
}
return data;
}
/**
* Parses one line of csv entries into the desired type of object.
* @param parts The csv entries of a line.
* @return Object of desired type.
*/
public abstract T parse(String[] parts);
}
...@@ -27,7 +27,7 @@ import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor; ...@@ -27,7 +27,7 @@ import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
*/ */
public class CustomDistribution implements Distribution { public class CustomDistribution implements Distribution {
private Random rand = Randoms.getRandom(this); private Random rand = Randoms.getRandom(CustomDistribution.class);
private String csvFile = ""; private String csvFile = "";
......
...@@ -50,7 +50,8 @@ public class ExponentialDistribution implements Distribution { ...@@ -50,7 +50,8 @@ public class ExponentialDistribution implements Distribution {
if (distr == null) throw new ConfigurationException("Mu was not set for exponential distribution " + this); if (distr == null) throw new ConfigurationException("Mu was not set for exponential distribution " + this);
double random = Randoms.getRandom(this).nextDouble(); double random = Randoms.getRandom(ExponentialDistribution.class)
.nextDouble();
double result; double result;
try { try {
......
...@@ -132,7 +132,9 @@ public class LimitedNormalDistribution implements Distribution { ...@@ -132,7 +132,9 @@ public class LimitedNormalDistribution implements Distribution {
} }
public double returnValue() { public double returnValue() {
double random = pmin + Randoms.getRandom(this).nextDouble() * pfactor; double random = pmin
+ Randoms.getRandom(LimitedNormalDistribution.class)
.nextDouble() * pfactor;
double result; double result;
try { try {
......
...@@ -22,10 +22,10 @@ ...@@ -22,10 +22,10 @@
package de.tud.kom.p2psim.impl.util.stat.distributions; package de.tud.kom.p2psim.impl.util.stat.distributions;
import umontreal.iro.lecuyer.probdist.LognormalDist;
import de.tudarmstadt.maki.simonstrator.api.Randoms; import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.util.Distribution; import de.tudarmstadt.maki.simonstrator.api.util.Distribution;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor; import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
import umontreal.iro.lecuyer.probdist.LognormalDist;
public class LognormalDistribution implements Distribution { public class LognormalDistribution implements Distribution {
...@@ -48,7 +48,8 @@ public class LognormalDistribution implements Distribution { ...@@ -48,7 +48,8 @@ public class LognormalDistribution implements Distribution {
} }
public double returnValue() { public double returnValue() {
double random = Randoms.getRandom(this).nextDouble(); double random = Randoms.getRandom(LognormalDistribution.class)
.nextDouble();
double result = 0; double result = 0;
try { try {
......
...@@ -22,10 +22,10 @@ ...@@ -22,10 +22,10 @@
package de.tud.kom.p2psim.impl.util.stat.distributions; package de.tud.kom.p2psim.impl.util.stat.distributions;
import umontreal.iro.lecuyer.probdist.LognormalDist;
import de.tudarmstadt.maki.simonstrator.api.Randoms; import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.util.Distribution; import de.tudarmstadt.maki.simonstrator.api.util.Distribution;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor; import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
import umontreal.iro.lecuyer.probdist.LognormalDist;
public class MixedLogNormalDistribution implements Distribution { public class MixedLogNormalDistribution implements Distribution {
...@@ -65,7 +65,8 @@ public class MixedLogNormalDistribution implements Distribution { ...@@ -65,7 +65,8 @@ public class MixedLogNormalDistribution implements Distribution {
} }
public double returnValue() { public double returnValue() {
double random = Randoms.getRandom(this).nextDouble(); double random = Randoms.getRandom(MixedLogNormalDistribution.class)
.nextDouble();
double result = 0; double result = 0;
try { try {
result = weight1 * distr1.inverseF(random) + weight2 result = weight1 * distr1.inverseF(random) + weight2
......
...@@ -35,7 +35,7 @@ public class NormalDistribution implements Distribution { ...@@ -35,7 +35,7 @@ public class NormalDistribution implements Distribution {
private NormalDistributionImpl normal; private NormalDistributionImpl normal;
private Random randomGen = Randoms.getRandom(this); private Random randomGen = Randoms.getRandom(NormalDistribution.class);
private double mu; private double mu;
......
...@@ -42,7 +42,7 @@ public class PoissonDistribution implements Distribution { ...@@ -42,7 +42,7 @@ public class PoissonDistribution implements Distribution {
// returns the x-value for a random value in the cdf // returns the x-value for a random value in the cdf
public double returnValue() { public double returnValue() {
double random = Randoms.getRandom(this) double random = Randoms.getRandom(PoissonDistribution.class)
.nextDouble(); .nextDouble();
int result; int result;
......
...@@ -50,7 +50,8 @@ public class UniformDistribution implements Distribution { ...@@ -50,7 +50,8 @@ public class UniformDistribution implements Distribution {
*/ */
public double returnValue() { public double returnValue() {
return min + factor * Randoms.getRandom(this).nextDouble(); return min + factor
* Randoms.getRandom(UniformDistribution.class).nextDouble();
} }
/** /**
......
...@@ -66,7 +66,8 @@ public class ZipfDistribution implements Distribution { ...@@ -66,7 +66,8 @@ public class ZipfDistribution implements Distribution {
// rank = 1 ... maximum_Number_Of_Ranks => 1/rank = 0..1 // rank = 1 ... maximum_Number_Of_Ranks => 1/rank = 0..1
return 1 / (Math return 1 / (Math
.pow(1 / (Randoms.getRandom(this).nextDouble() * harmonicNormFactor), .pow(1 / (Randoms.getRandom(ZipfDistribution.class).nextDouble()
* harmonicNormFactor),
1 / zipfExponent)); 1 / zipfExponent));
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment