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

Methods for interacting with the 5G-view

Merge remote-tracking branch 'origin/master'
parents 1a52704a 1c3059af
......@@ -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;
}
}
......@@ -51,8 +51,11 @@ public class ShowMapQuestMapViz extends JComponent
private BufferedImage background = null;
private BufferedImage storedImage;
private boolean initialized = false;
public ShowMapQuestMapViz() {
setBounds(0, 0, VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY());
......@@ -168,7 +171,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;
}
}
/**
......
......@@ -287,6 +287,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.
......@@ -590,7 +601,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())
......@@ -615,7 +629,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;
}
}
}
}
}
......@@ -627,7 +667,22 @@ public class VisualizationTopologyView extends JFrame
}
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() {
......
......@@ -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