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

Merge branch 'nr/monitoring-clemens' into 'master'

Merge nr/monitoring clemens into master

- added possibility to "destroy" cells in 5GTopologyDatabase and 5GVis using SHIFT + Left-Click - default FALSE
- added default black circle for drawing of nodes
- added differentiation for Mouse-Click, -Drag, -Release etc.
- deleted timoutcollections as they seem to be unused and are in overlays with initial behavior of Leo Nobach and extended by Nils Richerzhagen and Clemens Krug. Will be merged next.

See merge request !42
parents a7d442fb 9c2e5caf
......@@ -21,8 +21,18 @@
package de.tud.kom.p2psim.impl.topology.movement.modularosm.mapvisualization;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
public interface IMapVisualization{
public void paint(Graphics g);
/**
* Retreives the current map as image.
* @return image of the current map
*/
default BufferedImage getMapImage()
{
return null;
}
}
......@@ -48,8 +48,11 @@ public class ShowMapQuestMapViz extends JComponent
private String mapQuestKey;
private BufferedImage storedImage;
private boolean initialized = false;
public ShowMapQuestMapViz() {
setBounds(0, 0, VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY());
......@@ -149,7 +152,23 @@ public class ShowMapQuestMapViz extends JComponent
RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(originalImage, 0, 0, width, height, this);
g.dispose();
storedImage = resizedImage;
return resizedImage;
}
@Override
public BufferedImage getMapImage()
{
if(storedImage == null)
{
initializeImage();
resize(Toolkit.getDefaultToolkit().getImage(tempImageFilePath),
VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY());
}
return storedImage;
}
}
......@@ -124,7 +124,7 @@ public class DefaultLink implements Link {
* @return
*/
@Override
public final boolean isConnected() {
public boolean isConnected() {
return isConnected;
}
......
......@@ -336,7 +336,7 @@ public class FiveGTopologyView extends AbstractTopologyView<CellLink> {
/**
* GroupIDs that act as clients and have access to access points.
*
* @param cloudletGroups
* @param accessPointGroups
*/
@SuppressWarnings("unchecked")
public void setAccessPointGroups(String[] accessPointGroups) {
......@@ -484,6 +484,14 @@ public class FiveGTopologyView extends AbstractTopologyView<CellLink> {
: linkData.getLatency(isUpload);
}
@Override
public boolean isConnected()
{
if(apLinkData != null) return apLinkData.getConnectivity();
if(linkData != null) return linkData.getConnectivity();
return false;
}
}
/**
......
......@@ -32,12 +32,7 @@ import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.util.Collection;
import java.util.HashMap;
......@@ -46,16 +41,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.Timer;
import javax.swing.*;
import com.google.common.collect.Maps;
......@@ -153,6 +139,7 @@ public class VisualizationTopologyView extends JFrame
this.setPreferredSize(new Dimension(800, 600));
this.setExtendedState(Frame.MAXIMIZED_BOTH);
Thread t = new Thread(this);
t.start();
}
......@@ -284,6 +271,17 @@ public class VisualizationTopologyView extends JFrame
* obstacle); worldPanel.add(obsVis); } }
*/
/**
* Sets a node to clicked or unclicked state
* @param id The node which should be affected
* @param clicked true if the node should be set as clicked, false otherwise
*/
public void toggleNodeClicked(INodeID id, boolean clicked)
{
worldPanel.nodeInformation.get(id).clicked = clicked;
}
@Override
public void onLocationChanged(Host host, Location location) {
// The NodeInformation objects are registered as listener.
......@@ -345,9 +343,9 @@ public class VisualizationTopologyView extends JFrame
VisualizationInjector.scaleValue(location.getLongitude()),
VisualizationInjector.scaleValue(location.getLatitude()));
}
}
/**
* The world
*
......@@ -402,6 +400,7 @@ public class VisualizationTopologyView extends JFrame
});
}
public void addTopologyComponent(TopologyComponent comp) {
if (!nodeInformation.containsKey(comp.getHost().getId())) {
NodeInformation tVis = new NodeInformation(comp);
......@@ -428,11 +427,16 @@ public class VisualizationTopologyView extends JFrame
private void paintNodes(Graphics2D g2) {
for (NodeInformation node : nodeInformation.values()) {
// TODO FIXME add way to provide draw() impl for nodes
if (node.clicked) {
g2.setColor(Color.MAGENTA);
g2.fillOval((int) node.position.getX() - PADDING,
(int) node.position.getY() - PADDING,
PADDING * 2 + 1, PADDING * 2 + 1);
} else {
g2.setColor(Color.BLACK);
g2.fillOval((int) node.position.getX() - 2,
(int) node.position.getY() - 2, 5, 5);
}
}
}
......@@ -566,7 +570,10 @@ public class VisualizationTopologyView extends JFrame
public void eventDispatched(AWTEvent e) {
if (e instanceof MouseEvent) {
MouseEvent me = (MouseEvent) e;
if (me.getID() == MouseEvent.MOUSE_CLICKED) {
if (me.getID() == MouseEvent.MOUSE_CLICKED
|| me.getID() == MouseEvent.MOUSE_DRAGGED
|| me.getID() == MouseEvent.MOUSE_PRESSED
|| me.getID() == MouseEvent.MOUSE_RELEASED) {
// Another dirty hack until we have another graphic
// drawing system
if (((JFrame) worldPanel.getTopLevelAncestor())
......@@ -591,7 +598,33 @@ public class VisualizationTopologyView extends JFrame
.getY();
for (MouseClickListener l : mouseListeners) {
l.mouseClicked(x, y);
if (me.getID() == MouseEvent.MOUSE_CLICKED) {
l.mouseClicked(x, y);
l.mouseClicked(x, y, me.getModifiers());
} else {
if (l instanceof MouseListener) {
switch (me.getID()) {
case MouseEvent.MOUSE_DRAGGED:
((MouseListener) l)
.mouseDragged(x, y);
break;
case MouseEvent.MOUSE_PRESSED:
((MouseListener) l)
.mousePressed(x, y);
break;
case MouseEvent.MOUSE_RELEASED:
((MouseListener) l)
.mouseReleased(x,
y);
break;
default:
break;
}
}
}
}
}
......@@ -602,8 +635,24 @@ public class VisualizationTopologyView extends JFrame
}, eventMask);
}
public static interface MouseClickListener {
public void mouseClicked(int x, int y);
@Deprecated
/**
* Method is deprecated. Uses mouseClicked(int x, int y, int modifier) instead.
*/
default void mouseClicked(int x, int y){}
default void mouseClicked(int x, int y, int modifier) {}
}
public interface MouseListener extends MouseClickListener {
void mouseDragged(int x, int y);
void mousePressed(int x, int y);
void mouseReleased(int x, int y);
}
public static JComponent getWorldPanel() {
......@@ -618,6 +667,7 @@ public class VisualizationTopologyView extends JFrame
mouseListeners.remove(listener);
}
/**
* Listener is informed, whenever the user clicks on a node
*
......
......@@ -27,6 +27,7 @@ import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.Visualiza
import de.tud.kom.p2psim.impl.topology.views.visualization.world.FiveGVisualization;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* Abstract base class working on grids of configurable size.
......@@ -46,6 +47,8 @@ public abstract class AbstractGridBasedTopologyDatabase
private final Map<Integer, FiveGTopologyDatabase.Entry> cloudletEntries;
public static int _visId = 1;
private boolean enableCellDestruction = false;
/**
* Grid-based {@link CellularTopologyDatabase} with a grid length (squares)
......@@ -68,12 +71,17 @@ public abstract class AbstractGridBasedTopologyDatabase
public void eventOccurred(Object content, int type) {
VisualizationInjector.injectComponent("5G " + _visId++, -1,
new FiveGVisualization(
AbstractGridBasedTopologyDatabase.this),
AbstractGridBasedTopologyDatabase.this, enableCellDestruction),
false, true);
}
}, null, 0);
}
}
public void setEnableCellDestruction(boolean enableCellDestruction){
this.enableCellDestruction = enableCellDestruction;
}
public void setGridSize(int gridSize) {
this.gridSize = gridSize;
......@@ -141,6 +149,8 @@ public abstract class AbstractGridBasedTopologyDatabase
private final long latencyUp, latencyDown, bandwidthUp, bandwidthDown;
private boolean connectivity = true;
/**
* Segment offering both, cell and access point with different
......@@ -173,19 +183,40 @@ public abstract class AbstractGridBasedTopologyDatabase
@Override
public double getDropProbability(boolean isUpload) {
if(!getConnectivity()){
return 1;
}
return isUpload ? dropUp : dropDown;
}
@Override
public long getLatency(boolean isUpload) {
if(!getConnectivity()){
return 9999 * Time.MILLISECOND;
}
return isUpload ? latencyUp : latencyDown;
}
@Override
public long getBandwidth(boolean isUpload) {
if(!getConnectivity()){
return 0;
}
return isUpload ? bandwidthUp : bandwidthDown;
}
@Override
public boolean getConnectivity()
{
return connectivity;
}
@Override
public void setConnectivity(boolean connectivity)
{
this.connectivity = connectivity;
}
}
}
......@@ -24,8 +24,12 @@ import de.tud.kom.p2psim.impl.topology.views.FiveGTopologyView;
import de.tud.kom.p2psim.impl.topology.views.FiveGTopologyView.CellLink;
/**
* Database for the {@link FiveGTopologyView} - containing a mapping of
* position IDs to the respective link characteristics.
* Database for the {@link FiveGTopologyView} - containing a mapping of position
* IDs to the respective link characteristics.
*
* 06.10.2016 added by Nils Richerzhagen, Clemens Krug Functionality to
* 'destroy' cells using SHIFT + Left-click. Enable/Disable using the
* enableCellDestruction boolean.
*
* @author Bjoern Richerzhagen
* @version 1.0, Nov 5, 2015
......@@ -59,6 +63,17 @@ public interface FiveGTopologyDatabase {
public FiveGTopologyDatabase.Entry getEntryFor(int segmentID,
boolean isCloudlet);
/**
* If wanted one can 'destroy' cells using this method. Destroy means that
* the cell is not available for the communication mean specified within
* that TopologyView.
*
* To be set by configuration.
*
* @param enableCellDestruction
*/
public void setEnableCellDestruction(boolean enableCellDestruction);
/**
* Data structure for the network parameters of a given segment ID - these
* are directly accessed by the {@link CellLink} object on each call (so
......@@ -101,6 +116,23 @@ public interface FiveGTopologyDatabase {
*/
public long getBandwidth(boolean isUpload);
/**
* Connectivity of the cell.
*
* @return <code>false</code> if the cell is broken down/damaged and
* upload/download isn't possible. <code>true</code> otherwise.
*/
boolean getConnectivity();
/**
* Set the connectivity of the cell. When set to <code>false</code>, it
* should be impossible to upload or download data via this cell.
* {@link CellLink} refers to this attribute when returning e.g. BW or
* drop rate.
*
* @param connectivity
*/
void setConnectivity(boolean connectivity);
}
}
......@@ -20,17 +20,6 @@
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.impl.topology.views.FiveGTopologyView;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.views.fiveg.AbstractGridBasedTopologyDatabase;
......@@ -38,21 +27,31 @@ import de.tud.kom.p2psim.impl.topology.views.fiveg.FiveGTopologyDatabase.Entry;
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;
/**
* 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
*
* @author Bjoern Richerzhagen
* @version 1.0, Nov 5, 2015
*/
public class FiveGVisualization extends JComponent {
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) {
public FiveGVisualization(AbstractGridBasedTopologyDatabase database, boolean enableCellDestruction) {
setBounds(0, 0, VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY());
setOpaque(true);
......@@ -61,6 +60,10 @@ public class FiveGVisualization extends JComponent {
this.database = database;
image = new BufferedImage(VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY(), BufferedImage.TYPE_INT_ARGB);
this.enableCellDestruction = enableCellDestruction;
VisualizationInjector.addMouseListener(this);
}
@Override
......@@ -91,6 +94,8 @@ public class FiveGVisualization extends JComponent {
try {
drawEntries(g2);
} catch (RuntimeException e) {
e.printStackTrace();
System.exit(0);
needsRedraw = true;
}
}
......@@ -112,10 +117,10 @@ public class FiveGVisualization extends JComponent {
if (entry == null) {
continue;
}
if (entry.getLatency(isUpload) > maxLatency) {
if (entry.getConnectivity() && entry.getLatency(isUpload) > maxLatency) {
maxLatency = entry.getLatency(isUpload);
}
if (entry.getLatency(isUpload) < minLatency) {
if (entry.getConnectivity() && entry.getLatency(isUpload) < minLatency) {
minLatency = entry.getLatency(isUpload);
}
}
......@@ -135,17 +140,17 @@ public class FiveGVisualization extends JComponent {
// TODO add checkbox for upload/download toggle?
// Latency
double latencyFactor = (entry.getLatency(isUpload) - minLatency)
/ (maxLatency - minLatency);
double latencyFactor = entry.getConnectivity() ? (entry.getLatency(isUpload) - minLatency)
/ (maxLatency - minLatency) : 4;
g2.setColor(
new Color(255, 0, 0, 10 + (int) (40 * latencyFactor)));
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))));
g2.setStroke(new BasicStroke(
(float) (10 * entry.getDropProbability(isUpload))));
float strokeWidth = entry.getConnectivity() ? (float) entry.getDropProbability(isUpload) : 0.2f;
g2.setStroke(new BasicStroke((10 * strokeWidth)));
g2.drawRect(x, y, stepSize, stepSize);
g2.setColor(new Color(255, 255, 255, 255));
g2.drawString("L: "
......@@ -158,9 +163,25 @@ public class FiveGVisualization extends JComponent {
g2.drawString("BW: "
+ (int) (entry.getBandwidth(isUpload) / Rate.kbit_s)
+ " kBit/s", x + 10, y + 35);
if(!entry.getConnectivity())
{
g2.drawString("!DEAD!", x + 30, y + 70);
}
}
}
}
@Override
public void mouseClicked(int x, int y, int modifier)
{
// 17 == Shift
if(enableCellDestruction && modifier == 17)
{
int segID = database.getSegmentID(x, y);
Entry entry = database.getEntryFor(segID, false);
entry.setConnectivity(!entry.getConnectivity());
needsRedraw = true;
}
}
}
/*
* Copyright (c) 2005-2011 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.util.timeoutcollections;
/**
* Listens to entry timeouts of timeout maps. For efficiency reasons, an event is
* fired only when the map is cleaned up, not in real time. This is done after every
* cleanup process in the timeout set. So the firing of the timeout event may occur after
* the element would literally timeout.
*
* @author Leo Nobach
*
* @param <E>
*/
public interface ITimeoutMapListener<K, V> {
/**
* Called when an entry in the timeout map has timed out.
*
* @param set , the timeout map where the event occurred.
* @param key , the key that timed out
* @param value , the value that timed out
* @param timeoutTime , the time when the event's timeout was actually set,
* this may not be the current time.
*/
public void elementTimeouted(TimeoutMap map, K key, V value,
long timeoutTime);
}
\ No newline at end of file
/*
* Copyright (c) 2005-2011 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.util.timeoutcollections;
/**
* Listens to element timeouts of timeout sets. For efficiency reasons, an event is
* fired only when the set is cleaned up, not in real time. This is done after every
* cleanup process in the timeout set. So the firing of the timeout event may occur after
* the element would literally timeout.
*
* @author Leo Nobach
*
* @param <E>
*/
public interface ITimeoutSetListener<E> {
/**
* Called when an element in the timeout set has timed out.
* @param set , the timeout set where the event occurred.
* @param element , the element that was removed.
* @param timeoutTime , the time when the event's timeout was actually set, this may not be the current time.
*/
public void elementTimeouted(TimeoutSet set, E element, long timeoutTime);
}
\ No newline at end of file
/*
* Copyright (c) 2005-2013 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.util.timeoutcollections;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import com.google.common.collect.Lists;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* Holds a counter that is increased for a given
* time period. After the specified timeout the
* counter will be reduced by the amount it has
* been increased.
*
* @author Fabio Zöllner
* @version 1.0, 19.01.13
*/
public class TimeoutCounter {
private long defaultTimeout;
private int count = 0;
private List<Long> timeouts = Lists.newArrayList();
public TimeoutCounter(long defaultTimeout) {
this.defaultTimeout = defaultTimeout;
}
public void increase() {
count++;
timeouts.add(Time.getCurrentTime() + defaultTimeout);
}
public void increase(long timeout) {
count++;
timeouts.add(Time.getCurrentTime() + timeout);
}
public int get() {
cleanup();
return count;
}
private void cleanup() {
Collections.sort(timeouts);
long currentTime = Time.getCurrentTime();
for (Iterator<Long> iterator = timeouts.iterator(); iterator.hasNext(); ) {
Long next = iterator.next();
if (next <= currentTime) {
iterator.remove();
count--;
}
}
}
}
/*
* Copyright (c) 2005-2011 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.util.timeoutcollections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* A map of objects where elements 'run out' after a certain amount of time and get
* thrown out of the collection. Entry (k,v) (added via putNow(k,v)) is removed from this map
* after a defined timeout since it is added.
* <br><br>
* You can add listeners to this set that announce elements that are removed from
* this set during the cleanup process.
*
* @author Leo Nobach
*
* @param <E>
*/
public class TimeoutMap<K, V> {
Map<K, V> elements = new HashMap<K, V>();
Queue<TimeoutObject> timeQ = new LinkedBlockingQueue<TimeoutObject>();
List<ITimeoutMapListener<K, V>> listeners = new ArrayList<ITimeoutMapListener<K, V>>();
long timeout;
/**
* Creates a new TimeoutMap with the given timeout in simulation time units,
* i.e. the time until entry (k,v) (added via putNow(k,v)) is removed from this map.
* @param timeout , the time until entry (k,v) (added via putNow(k,v)) is removed from this map.
*/
public TimeoutMap(long timeout) {
this.timeout = timeout;
}
/**
* Puts an entry into this timeout map. The entry will
* time out in currentTime + timeout simulation time units.
* @param key
* @param value
*/
public void putNow(K key, V value) {
cleanup();
long time = getCurrentTime();
if (elements.containsKey(key))
timeQ.remove(new TimeoutObject(key, 0));
elements.put(key, value);
timeQ.add(new TimeoutObject(key, time + timeout));
assertSet();
}
/**
* Returns whether this set contains the specified key.
* Behaves like java.util.Map
* @param element
* @return
*/
public boolean containsKey(K key) {
cleanup();
assertSet();
return elements.containsKey(key);
}
/**
* Returns an unmodifiable Map view of this TimeoutMap.
* @return
*/
public Map<K, V> getUnmodifiableMap() {
cleanup();
return Collections.unmodifiableMap(elements);
}
/**
* Removes the entry with the given key from this map, although
* it is not timed out.
* Behaves like java.util Map
* @param key
* @return
*/
public boolean remove(K key) {
// System.out.println("Q+SET-BEFORE: " + timeQ + ", " + elements +
// " REMOVING: " + element);
cleanup();
boolean result = false;
if (elements.containsKey(key)) {
result = true;
timeQ.remove(new TimeoutObject(key, 0));
// System.out.println("SET CONTAINS ELEMENT");
}
elements.remove(key);
assertSet();
return result;
}
/**
* Returns the value associated with the given key.
* Behaves like java.util.Map
* @param key
* @return
*/
public V get(K key) {
cleanup();
return elements.get(key);
}
/**
* Returns the size of this TimeoutMap. Behaves like
* java.util.Map
* @return
*/
public int size() {
cleanup();
return elements.size();
}
private void assertSet() {
if (elements.size() != timeQ.size())
throw new AssertionError("Inequal sizes of queue and set: "
+ timeQ.size() + ", " + elements.size());
}
/**
* Cleans up this map. Calling this method does not change anything in the semantics
* of the TimeoutMap, but should be done when you want to purge old entries from memory.
* Automatically done through other methods, if needed.
*/
public void cleanup() {
long time = getCurrentTime();
while (!timeQ.isEmpty() && timeQ.element().timeout <= time) {
TimeoutObject obj = timeQ.remove();
V value = elements.remove(obj.object);
elementTimeouted(obj.object, value, obj.timeout);
}
assertSet();
}
protected long getCurrentTime() {
return Time.getCurrentTime();
}
/**
* Adds an ITimeoutMapListener to this TimeoutMap.
* @param l
*/
public void addListener(ITimeoutMapListener<K, V> l) {
listeners.add(l);
}
protected void elementTimeouted(K key, V value, long timeoutTime) {
for (ITimeoutMapListener<K, V> l : listeners)
l.elementTimeouted(this, key, value, timeoutTime);
}
protected class TimeoutObject {
public TimeoutObject(K object, long timeout) {
this.object = object;
this.timeout = timeout;
}
public K object;
public long timeout;
public boolean equals(Object o) {
return ((TimeoutObject) o).object.equals(this.object);
}
public int hashCode() {
return this.object.hashCode();
}
}
}
/*
* Copyright (c) 2005-2011 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.util.timeoutcollections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* A set of objects where elements 'run out' after a certain amount of time and get
* thrown out of the collection. Element e (added via addNow(e)) is removed from this set
* after a defined timeout since it is added.
* <br><br>
* You can add listeners to this set that announce elements that are removed from
* this set during the cleanup process.
*
* @author Leo Nobach
*
* @param <E>
*/
public class TimeoutSet<E> {
Set<E> elements = new LinkedHashSet<E>();
Queue<TimeoutObject> timeQ = new LinkedBlockingQueue<TimeoutObject>();
List<ITimeoutSetListener<E>> listeners = new ArrayList<ITimeoutSetListener<E>>();
long timeout;
/**
* Creates a new TimeoutSet with the given timeout in simulation time units,
* i.e. the time until element e (added via addNow(e)) is removed from this set.
* @param timeout , the time until element e (added via addNow(e)) is removed from this set.
*/
public TimeoutSet(long timeout) {
this.timeout = timeout;
}
/**
* Removes the oldest element that is currently i this set.
* @return
*/
public E removeOldest() {
cleanup();
TimeoutObject obj = timeQ.remove();
elements.remove(obj.object);
//assertSet();
return obj.object;
}
public String toString() {
return elements.toString();
}
/**
* Returns an unmodifiable view of this timeout set, using
* the interface java.util.Set
* @return
*/
public Set<E> getUnmodifiableSet() {
cleanup();
return Collections.unmodifiableSet(elements);
}
/**
* Adds an element to this timeout set. The element will
* time out in currentTime + timeout simulation time units.
* @param element
*/
public void addNow(E element) {
cleanup();
long time = getCurrentTime();
if (elements.contains(element))
timeQ.remove(new TimeoutObject(element, 0));
elements.add(element);
timeQ.add(new TimeoutObject(element, time + timeout));
//assertSet();
}
/**
* Returns whether this set contains the specified element.
* Behaves like java.util.Set
* @param element
* @return
*/
public boolean contains(E element) {
cleanup();
//assertSet();
return elements.contains(element);
}
/**
* Removes the given element from this set, although if it is
* not timeouted.
* Returns whether the given element was contained in this set.
*
* @param element
* @return
*/
public boolean remove(E element) {
// System.out.println("Q+SET-BEFORE: " + timeQ + ", " + elements +
// " REMOVING: " + element);
cleanup();
boolean result = false;
if (elements.contains(element)) {
result = true;
timeQ.remove(new TimeoutObject(element, 0));
// System.out.println("SET CONTAINS ELEMENT");
}
elements.remove(element);
//assertSet();
return result;
}
/**
* Returns the size of this timeout set. Works like in java.util.Set
*/
public int size() {
cleanup();
return elements.size();
}
/**
* Returns whether this timeout set is empty. Works like in java.util.Set
* @return
*/
public boolean isEmpty() {
return size() == 0;
}
/*
private void assertSet() {
if (elements.size() != timeQ.size())
throw new AssertionError("Inequal sizes of queue and set: "
+ timeQ.size() + ", " + elements.size());
}
*/
/**
* Cleans up this set. Calling this method does not change anything in the semantics
* of the TimeoutSet, but should be done when you want to purge old elements from memory.
* Automatically done by other methods.
*
*/
public void cleanup() {
long time = getCurrentTime();
while (!timeQ.isEmpty() && timeQ.element().timeout <= time) {
TimeoutObject obj = timeQ.remove();
elements.remove(obj.object);
elementTimeouted(obj.object, obj.timeout);
}
//assertSet();
}
protected long getCurrentTime() {
return Time.getCurrentTime();
}
/**
* Adds a new ITimeoutCollectionListener to this timeout set.
* @param l
*/
public void addListener(ITimeoutSetListener<E> l) {
listeners.add(l);
}
protected void elementTimeouted(E element, long timeoutTime) {
for (ITimeoutSetListener<E> l : listeners)
l.elementTimeouted(this, element, timeoutTime);
}
protected class TimeoutObject {
public TimeoutObject(E object, long timeout) {
this.object = object;
this.timeout = timeout;
}
public E object;
public long timeout;
public boolean equals(Object o) {
return ((TimeoutObject) o).object.equals(this.object);
}
public int hashCode() {
return this.object.hashCode();
}
}
}
/*
* Copyright (c) 2005-2013 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.util.timeoutcollections;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* Holds a counter that is increased for a given time period. After the
* specified timeout the counter will be reduced by the amount it has been
* increased.
*
* @author Fabio Zöllner
* @version 1.0, 19.01.13
*/
public class TimeoutSum {
private long defaultTimeout;
private long count = 0;
private List<Tuple<Long, Long>> timeouts;
public TimeoutSum(long defaultTimeout) {
this.defaultTimeout = defaultTimeout;
timeouts = new LinkedList<TimeoutSum.Tuple<Long, Long>>();
}
public void increase(long value) {
count += value;
timeouts.add(new Tuple<Long, Long>(Time.getCurrentTime() + defaultTimeout, value));
}
public void increase(long value, long timeout) {
count += value;
timeouts.add(new Tuple<Long, Long>(Time.getCurrentTime() + timeout, value));
Collections.sort(timeouts, new Comparator<Tuple<Long, Long>>() {
@Override
public int compare(Tuple<Long, Long> o1, Tuple<Long, Long> o2) {
return o2.x.compareTo(o1.x);
}
});
}
public long get() {
cleanup();
return count;
}
private void cleanup() {
long currentTime = Time.getCurrentTime();
for (Iterator<Tuple<Long, Long>> iterator = timeouts.iterator(); iterator.hasNext();) {
Tuple<Long, Long> next = iterator.next();
if (next.x <= currentTime) {
iterator.remove();
count -= next.y;
}
}
}
private class Tuple<X, Y> {
public final X x;
public final Y y;
public Tuple(X x, Y y) {
this.x = x;
this.y = y;
}
}
}
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