Commit aa205068 authored by Nils Richerzhagen's avatar Nils Richerzhagen
Browse files

Merge branch 'nr/resAlloc-clemens' into 'nr/monitoring-req-resp'

Merge Nr/res alloc clemens into nr/monitoring-req-resp

See merge request !10
parents fb48b989 28159a91
package de.tud.kom.p2psim.impl.topology.movement.modularosm.transition;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import java.util.*;
/**
* This {@link ITransitionStrategy} works with manual assignments. Initially components will be assigned
* one of the attraction points, but at any further point, the set list of attraction points doesn't really matter.
* New target can be assigned by using the {@link #updateTargetAttractionPoint(SimLocationActuator, AttractionPoint)} method,
* otherwise the components will stop moving upon reaching their target.
*
* @author Clemens Krug
*/
public class ManualAssignmentStrategy implements ITransitionStrategy
{
private LinkedHashSet<AttractionPoint> aPoints = new LinkedHashSet<>();
private Map<SimLocationActuator, AttractionPoint> assignments = new HashMap<>();
private List<AttractionAssignmentListener> listeners = new LinkedList<>();
@Override
public AttractionPoint getAssignment(SimLocationActuator comp)
{
return assignments.get(comp);
}
@Override
public void addAttractionAssignmentListener(AttractionAssignmentListener listener)
{
listeners.add(listener);
}
@Override
public void removeAttractionAssignmentListener(AttractionAssignmentListener listener)
{
listeners.remove(listener);
}
@Override
public void setAttractionPoints(Collection<AttractionPoint> attractionPoints) {
aPoints.addAll(attractionPoints);
}
@Override
public Set<AttractionPoint> getAllAttractionPoints() {
return aPoints;
}
@Override
public void addComponent(SimLocationActuator ms) {
if(!assignments.containsKey(ms))
{
AttractionPoint aPoint = aPoints.iterator().next();
assignments.put(ms, aPoint);
}
listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, assignments.get(ms)));
}
@Override
public void reachedAttractionPoint(SimLocationActuator ms) {
//Nothing to do.
}
@Override
public void updateTargetAttractionPoint(SimLocationActuator comp, AttractionPoint attractionPoint) {
assignments.put(comp, attractionPoint);
listeners.forEach(listener -> listener.updatedAttractionAssignment(comp, attractionPoint));
}
}
package de.tud.kom.p2psim.impl.topology.movement.modularosm.transition;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.BasicAttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
import java.util.*;
/**
* This {@link ITransitionStrategy} makes clients move around randomly in a specified area. You can specify the target
* area center via the {@link #updateTargetAttractionPoint(SimLocationActuator, AttractionPoint)} method. The client will then start
* to roam the area randomly till a new target area is assigned.
*
* @author Clemens Krug
*/
public class RandomInAreaTransitionStrategy implements ITransitionStrategy
{
private Random random;
private LinkedHashSet<AttractionPoint> aPoints = new LinkedHashSet<>();
/**
* These are the target area centers the clients have assigned.
*/
private Map<SimLocationActuator, AttractionPoint> assignments = new HashMap<>();
/**
* These are the current spots inside the target area where the client is currently heading.
*/
private Map<SimLocationActuator, AttractionPoint> currentTarget = new HashMap<>();
private List<AttractionAssignmentListener> listeners = new LinkedList<>();
/**
* The radius the target area should have. Should be set via XML config file.
*/
private int defaultRadius;
public RandomInAreaTransitionStrategy()
{
random = Randoms.getRandom(this.getClass());
}
@Override
public AttractionPoint getAssignment(SimLocationActuator comp)
{
return currentTarget.get(comp);
}
@Override
public void addAttractionAssignmentListener(AttractionAssignmentListener listener)
{
listeners.add(listener);
}
@Override
public void removeAttractionAssignmentListener(AttractionAssignmentListener listener)
{
listeners.remove(listener);
}
@Override
public void setAttractionPoints(Collection<AttractionPoint> attractionPoints) {
aPoints.addAll(attractionPoints);
}
@Override
public Set<AttractionPoint> getAllAttractionPoints() {
return aPoints;
}
@Override
public void addComponent(SimLocationActuator ms) {
if(!assignments.containsKey(ms))
{
AttractionPoint aPoint = aPoints.iterator().next();
assignments.put(ms, aPoint);
currentTarget.put(ms, nextRandomPosition(aPoint, defaultRadius));
}
listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, currentTarget.get(ms)));
}
@Override
public void reachedAttractionPoint(SimLocationActuator ms) {
currentTarget.put(ms, nextRandomPosition(assignments.get(ms), defaultRadius));
listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, currentTarget.get(ms)));
}
@Override
public void updateTargetAttractionPoint(SimLocationActuator comp, AttractionPoint attractionPoint) {
assignments.put(comp, attractionPoint);
currentTarget.put(comp, nextRandomPosition(attractionPoint, defaultRadius));
listeners.forEach(listener -> listener.updatedAttractionAssignment(comp, attractionPoint));
}
public void setDefaultRadius(int radius)
{
this.defaultRadius = radius;
}
/**
* Calculates a random point within a given circular area.
* @param center The center of the area.
* @param radius The radius of the area.
* @return A random position within the area.
*/
private BasicAttractionPoint nextRandomPosition(Location center, int radius)
{
assert defaultRadius > 0 : "An area radius must be specified for the RandomInAreaTransitionStrategy! Did you set the 'DefaultRadius' property for this transition?";
double x = center.getLongitude();
double y = center.getLatitude();
double newX = -1;
double newY = -1;
int tries = 0;
while(newX < 0.0 || newX > Binder.getComponentOrNull(Topology.class).getWorldDimensions().getX()
|| newY < 0.0 || newY > Binder.getComponentOrNull(Topology.class).getWorldDimensions().getY())
{
double calcRadius = random.nextDouble() * radius;
double calcAngle = random.nextDouble() * 360;
newX = x + Math.sin(calcAngle) * calcRadius;
newY = y + Math.cos(calcAngle) * calcRadius;
tries++;
if(tries > 100) throw new AssertionError("Unable to find a valid target destination within <100 tries.");
}
Monitor.log(this.getClass(), Monitor.Level.DEBUG, "Next random position is " + newX + " / " + newY);
return new BasicAttractionPoint("RNDPOS", new PositionVector(newX, newY));
}
}
......@@ -110,8 +110,8 @@ public class CsvPlacement implements PlacementModel {
if (XY.getX() > world.getX() || XY.getY() > world.getY() || XY.getX() < 0
|| XY.getY() < 0) {
// System.err.println("Skipped entry " + x + ";"
// + y);
// System.err.println("Skipped entry " + x + ";"
// + y);
continue;
}
......
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
......@@ -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);
}
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