Commit 39035536 authored by Björn Richerzhagen's avatar Björn Richerzhagen
Browse files

Merge branch 'nr/monitoring-req-resp' into 'master'

Integrate Monitor-Peerfact/Bugfixes into master

See merge request !18
parents d7c80570 a721ca21
/*
* 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 @@
package de.tud.kom.p2psim.impl.topology.views.visualization.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.*;
import javax.swing.border.BevelBorder;
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 {
private static final int VIEW_WIDTH = 900;
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 String name;
private Map<String, XYChart> nameToPlotMap = Maps.newLinkedHashMap();
private JPanel content;
private JPanel selectorPanel;
private Box plotBox;
private GridBagConstraints layoutConstraints;
private JPanel plotBox;
private JScrollPane spane;
public PlottingView(String name) {
this.name = name;
setTitle(name);
setVisible(true);
......@@ -65,26 +61,16 @@ public class PlottingView extends JFrame {
}
private void buildUI() {
content = new JPanel();
content.setLayout(new BorderLayout());
selectorPanel = new JPanel();
selectorPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
layoutConstraints = new GridBagConstraints();
layoutConstraints.anchor = GridBagConstraints.NORTH;
layoutConstraints.weighty = 1;
plotBox = Box.createVerticalBox();
plotBox = new PlotBox();
plotBox.setLayout(new BoxLayout(plotBox, BoxLayout.Y_AXIS));
plotBox.setBackground(PLOT_BACKGROUND_COLOR);
plotBox.setBorder(BorderFactory.createEtchedBorder());
content.add(selectorPanel, BorderLayout.NORTH);
content.add(plotBox, BorderLayout.CENTER);
add(content, BorderLayout.CENTER);
spane = new JScrollPane(plotBox);
add(spane);
setSize(VIEW_WIDTH, VIEW_HEIGHT);
setPreferredSize(new Dimension(VIEW_WIDTH, VIEW_HEIGHT));
}
public XYChart createPlot(String name, String seriesName) {
......@@ -95,7 +81,8 @@ public class PlottingView extends JFrame {
chartPanel = wrapInCollabsable(chartPanel, name);
plotBox.add(chartPanel);
plotBox.validate();
plotBox.repaint();
spane.validate();
nameToPlotMap.put(name, plot);
......@@ -140,9 +127,12 @@ public class PlottingView extends JFrame {
if (collapseButton.getText().equals("-")) {
collapseButton.setText("+");
panel.remove(innerPanel);
panel.setMinimumSize(header.getPreferredSize());
panel.repaint();
} else {
collapseButton.setText("-");
panel.add(innerPanel, BorderLayout.CENTER);
panel.setMinimumSize(new Dimension(850,PLOT_HEIGHT_MIN));
}
}
});
......@@ -158,6 +148,7 @@ public class PlottingView extends JFrame {
panel.add(header, BorderLayout.NORTH);
panel.add(innerPanel, BorderLayout.CENTER);
panel.setMinimumSize(new Dimension(850,PLOT_HEIGHT_MIN));
return panel;
}
......@@ -165,7 +156,67 @@ public class PlottingView extends JFrame {
public void removeAllPlots() {
nameToPlotMap.clear();
plotBox.removeAll();
content.doLayout();
content.validate();
plotBox.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 @@
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.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.views.fiveg.AbstractGridBasedTopologyDatabase;
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.Time;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
/**
* Visualization for the {@link FiveGTopologyView}
*
* Added 06.10.2016 Nils Richerzhagen, Clemens Krug
* Functionality to 'destroy' cells using SHIFT + Left-click. Enable/Disable using the enableCellDestruction
* Added 06.10.2016 Nils Richerzhagen, Clemens Krug Functionality to 'destroy'
* 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
* @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;
protected BufferedImage image;
protected volatile boolean needsRedraw = true;
private final AbstractGridBasedTopologyDatabase database;
public FiveGVisualization(AbstractGridBasedTopologyDatabase database, boolean enableCellDestruction) {
public FiveGVisualization(AbstractGridBasedTopologyDatabase database,
boolean enableCellDestruction) {
setBounds(0, 0, VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY());
setOpaque(true);
......@@ -62,7 +78,7 @@ public class FiveGVisualization extends JComponent implements VisualizationInjec
VisualizationInjector.getWorldY(), BufferedImage.TYPE_INT_ARGB);
this.enableCellDestruction = enableCellDestruction;
VisualizationInjector.addMouseListener(this);
}
......@@ -108,70 +124,90 @@ public class FiveGVisualization extends JComponent implements VisualizationInjec
double minLatency = Double.MAX_VALUE;
boolean isUpload = false;
for (int x = 0; x < VisualizationInjector.getWorldX(); x += stepSize) {
for (int y = 0; y < VisualizationInjector
.getWorldY(); y += stepSize) {
// TODO add checkbox for cloudlets?
Entry entry = database.getEntryFor(database.getSegmentID(x, y),
false);
if (entry == null) {
continue;
try {
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) {
// TODO add checkbox for cloudlets?
Entry entry = database
.getEntryFor(database.getSegmentID(x, y), false);
if (entry == null) {
continue;
}
}
}
}
for (int x = 0; x < VisualizationInjector.getWorldX(); x += stepSize) {
for (int y = 0; y < VisualizationInjector
.getWorldY(); y += stepSize) {
// TODO add checkbox for cloudlets?
Entry entry = database.getEntryFor(database.getSegmentID(x, y),
false);
if (entry == null) {
continue;
}
// TODO add checkbox for upload/download toggle?
// Latency
double latencyFactor = (entry.getLatency(isUpload) - minLatency)
/ (maxLatency - minLatency);
g2.setColor(
new Color(255, 0, 0, 10 + (int) (40 * latencyFactor)));
g2.fillRect(x, y, stepSize, stepSize);
// Drop-Prob
g2.setColor(new Color(255, 0, 0,
10 + (int) (100 * entry.getDropProbability(isUpload))));
float strokeWidth = (float) entry.getDropProbability(isUpload);
g2.setStroke(new BasicStroke((10 * strokeWidth)));
g2.drawRect(x, y, stepSize, stepSize);
g2.setColor(new Color(255, 255, 255, 255));
g2.drawString("L: "
+ entry.getLatency(isUpload) / Time.MILLISECOND + " ms",
x + 10, y + 15);
g2.drawString(
"D: " + (int) (entry.getDropProbability(isUpload) * 100)
+ " %",
x + 10, y + 25);
g2.drawString("BW: "
+ (int) (entry.getBandwidth(isUpload) / Rate.kbit_s)
+ " kBit/s", x + 10, y + 35);
if(!entry.isAvailable()) {
g2.drawString("!DEAD!", x + 30, y + 70);
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) {
// TODO add checkbox for cloudlets?
Entry entry = database
.getEntryFor(database.getSegmentID(x, y), false);
if (entry == null) {
continue;
}
// TODO add checkbox for upload/download toggle?
// Latency
double latencyFactor = (entry.getLatency(isUpload)
- minLatency) / (maxLatency - minLatency);
g2.setColor(new Color(255, 0, 0,
10 + (int) (40 * latencyFactor)));
g2.fillRect(VisualizationInjector.scaleValue(x),
VisualizationInjector.scaleValue(y),
VisualizationInjector.scaleValue(stepSize),
VisualizationInjector.scaleValue(stepSize));
// Drop-Prob
g2.setColor(new Color(255, 0, 0, 10 + (int) (100
* entry.getDropProbability(isUpload))));
float strokeWidth = (float) entry
.getDropProbability(isUpload);
g2.setStroke(new BasicStroke((5 * strokeWidth)));
g2.drawRect(VisualizationInjector.scaleValue(x),
VisualizationInjector.scaleValue(y),
VisualizationInjector.scaleValue(stepSize),
VisualizationInjector.scaleValue(stepSize));
g2.setColor(new Color(255, 255, 255, 255));
g2.drawString("L: "
+ entry.getLatency(isUpload) / Time.MILLISECOND
+ " ms", VisualizationInjector.scaleValue(x + 10),
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
public void mouseClicked(int x, int y, int modifier)
{
public void mouseClicked(int x, int y, int modifier) {
// 17 == Shift
if(enableCellDestruction && modifier == 17)
{
int segID = database.getSegmentID(x, y);
if (enableCellDestruction && modifier == 17) {
int segID = database.getSegmentID(
VisualizationInjector.originalValue(x),
VisualizationInjector.originalValue(y));
Entry entry = database.getEntryFor(segID, false);
entry.setAvailability(!entry.isAvailable());
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
// Draw active (green) over underlay vis.
g2.setColor(nodeInfo.isActive() ? activeGreen : Color.LIGHT_GRAY);
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);
if (!nodeInfo.isActive()) {
......@@ -285,7 +285,7 @@ public class NodeInfoComponentVis extends JComponent
continue;
}
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));
......
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;
*/
public class CustomDistribution implements Distribution {
private Random rand = Randoms.getRandom(this);
private Random rand = Randoms.getRandom(CustomDistribution.class);
private String csvFile = "";
......
......@@ -50,7 +50,8 @@ public class ExponentialDistribution implements Distribution {
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;
try {
......
......@@ -132,7 +132,9 @@ public class LimitedNormalDistribution implements Distribution {
}
public double returnValue() {
double random = pmin + Randoms.getRandom(this).nextDouble() * pfactor;
double random = pmin
+ Randoms.getRandom(LimitedNormalDistribution.class)
.nextDouble() * pfactor;
double result;
try {
......
......@@ -22,10 +22,10 @@
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.util.Distribution;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
import umontreal.iro.lecuyer.probdist.LognormalDist;
public class LognormalDistribution implements Distribution {
......@@ -48,7 +48,8 @@ public class LognormalDistribution implements Distribution {
}
public double returnValue() {
double random = Randoms.getRandom(this).nextDouble();
double random = Randoms.getRandom(LognormalDistribution.class)
.nextDouble();
double result = 0;
try {
......
......@@ -22,10 +22,10 @@
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.util.Distribution;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
import umontreal.iro.lecuyer.probdist.LognormalDist;
public class MixedLogNormalDistribution implements Distribution {
......@@ -65,7 +65,8 @@ public class MixedLogNormalDistribution implements Distribution {
}
public double returnValue() {
double random = Randoms.getRandom(this).nextDouble();
double random = Randoms.getRandom(MixedLogNormalDistribution.class)
.nextDouble();
double result = 0;
try {
result = weight1 * distr1.inverseF(random) + weight2
......
......@@ -35,7 +35,7 @@ public class NormalDistribution implements Distribution {
private NormalDistributionImpl normal;
private Random randomGen = Randoms.getRandom(this);
private Random randomGen = Randoms.getRandom(NormalDistribution.class);
private double mu;
......
......@@ -42,7 +42,7 @@ public class PoissonDistribution implements Distribution {
// returns the x-value for a random value in the cdf
public double returnValue() {
double random = Randoms.getRandom(this)
double random = Randoms.getRandom(PoissonDistribution.class)
.nextDouble();
int result;
......
......@@ -50,7 +50,8 @@ public class UniformDistribution implements Distribution {
*/
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 {
// rank = 1 ... maximum_Number_Of_Ranks => 1/rank = 0..1
return 1 / (Math
.pow(1 / (Randoms.getRandom(this).nextDouble() * harmonicNormFactor),
.pow(1 / (Randoms.getRandom(ZipfDistribution.class).nextDouble()
* harmonicNormFactor),
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