www.pudn.com > JAVIS-0.3.zip > Scheduler.java
package animation;
import animation.*;
import animation.layout.*;
import iface.UserInterface;
import iface.VisualiserPanelObserver;
import iface.VisualiserPanel;
import fileio.*;
import fileio.event.*;
import math.*;
import util.Preferences;
import util.Debug;
import java.awt.Graphics;
import java.awt.Dimension;
import java.awt.Color;
import java.util.Enumeration;
/**
This class handles the main loop in the animation. It coordinates the
creation of elements at the correct time and controls the Thread for the
animation.
@author Christian Nentwich
@author Steven Vischer
@version 1.0
*/
public class Scheduler implements Animation, Runnable {
private double m_time; // The current time in seconds
private double m_timeinc; // Time increment in seconds
private UserInterface m_iface;
private Thread m_runthread; // Animation update thread
private VisualiserPanel m_panel; // The panel to draw onto
private java.util.Vector m_elements; // Dynamic elements (packets, etc.)
private java.util.Hashtable m_nodes;
private java.util.Hashtable m_queues;
private java.util.Vector m_links;
private FileIO m_fileio; // Trace file reader
private int m_filestatus; // One of the constants below
private final static int FILE_CLOSED = 0;
private final static int FILE_OPENED_RUN = 1;
private final static int FILE_EOF = 2;
private String m_filename; // Current tracefile name
private GraphLayoutManager m_layout; // The layout manager currently used
private boolean m_seekflag; // Flag for the thread if it needs
// to seek forward
/**
The only constructor. It will simply initialise all variables to
default. You have to pass the user interface that controls this
animation as an argument.
@param iface the UserInterface object that controls the animation.
*/
public Scheduler(UserInterface iface) {
m_time=0.0;
m_timeinc=0.025;
m_iface=iface;
m_fileio=new TraceFileReader();
m_runthread=null;
m_filestatus=FILE_CLOSED;
m_filename=null;
m_elements=null;
m_nodes=new java.util.Hashtable();
m_queues=new java.util.Hashtable();
m_links=new java.util.Vector();
m_seekflag=false;
}
/**
This function can (and must) be used to attach a panel that the
elements can draw onto.
@param panel the panel to draw onto
*/
public void attach(VisualiserPanel panel) {
if (m_panel==null)
m_panel=panel;
}
/**
loadFile will prescan the file given by its filename and extract the
static network structure. It will autolayout and draw the network on
the screen. It will also leave the file open for later playback.
@param filename the name of the trace-file to be loaded.
*/
public void loadFile(String filename) {
// Reset the time
m_time=0.0;
m_iface.setTimeBar(m_time);
// Get rid of any old elements
m_elements=null;
m_nodes=new java.util.Hashtable();
m_queues=new java.util.Hashtable();
m_links=new java.util.Vector();
// Start reading
TraceFileReader tr=new TraceFileReader();
m_elements=tr.prescanFile(filename);
Debug.out.println(m_elements.size());
// Sort nodes, links and queues into their real arrays. This is not
// proper OOP (check out the if-else bit) but serves the purpose
for (Enumeration e=m_elements.elements();e.hasMoreElements();) {
VisualElement element=(VisualElement)e.nextElement();
if (element instanceof Node)
m_nodes.put(new Integer(((Node)element).getNodeID()),element);
else
if (element instanceof Link)
m_links.addElement(element);
else
if (element instanceof Queue)
m_queues.put(new Integer(((Queue)element).getSource()),element);
}
// Go through all the links, find their corresponding end-node elements
// and attach them
for (Enumeration e=m_links.elements();e.hasMoreElements();) {
Link l=(Link)e.nextElement();
if (l==null) continue;
// !! TODO !! Check if either node does not exist. If so, offer a
// choice to disable the link or cancel loading.
Node s=(Node)m_nodes.get(new Integer(l.getSource()));
Node d=(Node)m_nodes.get(new Integer(l.getDestination()));
l.setSourceNode(s);
l.setDestNode(d);
s.addLink(d,l);
d.addLink(s,l);
}
Debug.out.println("");
Debug.out.println("Nodes: "+m_nodes.size());
Debug.out.println("Links: "+m_links.size());
//GK - added by Gabi Kliot
boolean USE_EXACT_LAYOUT = true;
if(USE_EXACT_LAYOUT){
m_layout=new ExactLayoutManager(m_nodes,m_links,
new Dimension(m_panel.getWidth(),
m_panel.getHeight()));
m_layout.doLayout(1);
m_panel.re_paint();
}
else{
// Do a random layout and afterwards a force autolayout
m_layout=new RandomLayoutManager(m_nodes,m_links,
new Dimension(m_panel.getWidth(),
m_panel.getHeight()));
m_layout.doLayout(1);
m_panel.re_paint();
// Now create a force layout manager
m_layout=new ForceLayoutManager(m_nodes,m_links,
new Dimension(m_panel.getWidth(),
m_panel.getHeight()),m_panel);
m_layout.doLayout(Preferences.layout_initial);
}
m_filename=filename;
m_filestatus=FILE_CLOSED;
m_elements=new java.util.Vector();
}
/**
startPlaying will create a new animation thread and start the update
loop. Of course, a file has to be loaded first and you must not be
playing already.
*/
public void startPlaying() {
// Open file if it's not open yet
if (m_filestatus==FILE_CLOSED) {
if (m_filename==null) return;
m_fileio.openFile(m_filename);
m_filestatus=FILE_OPENED_RUN;
}
// Thread is running at the moment, return quietly
if (m_runthread!=null) return;
// Otherwise start it
m_runthread=new Thread(this,"Animation Thread");
m_runthread.start();
}
/**
stopPlaying will kill the animation thread and stop playback almost
immediately. The thread has to be running otherwise it'll just return.
*/
public void stopPlaying() {
// No thread running
if (m_runthread==null) return;
// Stop the thread and join it
m_runthread.stop();
try {
m_runthread.join();
} catch(InterruptedException e) {}
m_runthread=null;
}
/**
Override the current time in the animation.
@param time the new current time in seconds
*/
public void setTime(double time) {
m_time=time;
}
/**
Returns the current time in the animation in seconds.
@return the current time in seconds
*/
public double getTime() {
return m_time;
}
/**
Set the curren time increment of the animation (the amount of time that
is being added every frame).
@param timeinc the new time increment in seconds
*/
public void setTimeInc(double timeinc) {
m_timeinc=timeinc;
}
/**
Return the current time increment of the animation (the amount of
time that is being added every frame).
@return the current time increment in seconds
*/
public double getTimeInc() {
return m_timeinc;
}
public void seekNext() {
// Don't seek if the animation is not running
if (m_runthread==null) return;
m_seekflag=true;
}
/**
Tell the Scheduler to rearrange the network layout on the screen. This
function will start a thread to do the layout and return control
immediately.
*/
public void reLayout() {
// Don't do autolayout if the animation is running
if (m_runthread!=null) return;
// Inner thread class to run the layout
class LThread implements Runnable {
public void run() {
for (int i=0;im_panel.getWidth()-10)
randx=m_panel.getWidth()-10;
if (randy<10) randy=10;
else
if (randy>m_panel.getHeight()-10)
randy=m_panel.getHeight()-10;
curnode.setX(randx);
curnode.setY(randy);
}
m_panel.re_paint();
try {
Thread.sleep(Preferences.fps);
} catch(InterruptedException exc) {}
}
}
}
// Start layout thread (TODO: Join the thread when it's done!!)
Thread t=new Thread(new LThread());
t.start();
}
/**
paint is called back by a panel to tell the Scheduler to redraw all
its elements. It shouldn't be used for other purposes.
@param g the graphics context to use for drawing.
*/
public void paint(Graphics g) {
// Fill background
g.setColor(new Color(0xdddddd));
g.fillRect(0,0,m_panel.getWidth(),m_panel.getHeight());
g.setColor(Color.black);
// Set font
g.setFont(new java.awt.Font("SansSerif",java.awt.Font.PLAIN,8));
// Get font settings
java.awt.FontMetrics metrics=g.getFontMetrics();
// Draw nodes
for (Enumeration e=m_nodes.elements();e.hasMoreElements();) {
Node n=(Node)e.nextElement();
n.draw(g,metrics);
}
// Draw links
for (Enumeration e=m_links.elements();e.hasMoreElements();) {
Link l=(Link)e.nextElement();
l.draw(g,metrics);
}
// Draw all the queues
if (m_queues!=null)
for (Enumeration e=m_queues.elements();e.hasMoreElements();) {
Queue q=(Queue)e.nextElement();
q.draw(g,metrics);
}
// Draw dynamic elements (packets, etc.)
if (m_elements!=null)
for (Enumeration e=m_elements.elements();e.hasMoreElements();) {
VisualElement ve=(VisualElement)e.nextElement();
ve.draw(g,metrics);
}
g.setColor(Color.white);
}
/**
handleEvent is used privately to dispatch events and updates elements.
It admittedly shows rather bad design. This function needs redesigning.
Lots of instanceof testing and casting is used. Events should maybe
be handled by VisualElement classes themselves.
*/
private void handleEvent(Event ev) {
if (ev instanceof LinkEvent) {
LinkEvent le=(LinkEvent)ev;
// Find the correct link through one of the nodes involved
Node s=(Node)m_nodes.get(new Integer(le.getSource()));
if (s==null) return;
Link l=s.getLink(le.getDestination());
if (l==null) return;
// Update status
//l.setColour(le.getColour());
l.setStatus(le.getStatus());
}
else
if (ev instanceof TextEvent) {
TextEvent te=(TextEvent)ev;
// Just add a Text object to the elements
Text t=(Text)te.returnElement();
m_elements.addElement(t);
}
else
if (ev instanceof NodeEvent) {
NodeEvent ne=(NodeEvent)ev;
// Update the node colour
Node n=(Node)m_nodes.get(new Integer(ne.getNodeID()));
n.setColour(ne.getColour());
}
else
if (ev instanceof StopEvent) {
StopEvent se=(StopEvent)ev;
this.stopPlaying();
}
else
if (ev instanceof PacketEvent) {
PacketEvent pe=(PacketEvent)ev;
// Packet events can be different kinds of events
switch (pe.getEventType()) {
case PacketEvent.ENQUE: { Queue q=(Queue)m_queues.get(new Integer(pe.getSource()));
Node s=(Node)m_nodes.get(new Integer(pe.getSource()));
// Queue not enable for display
if (q==null) break;
// Add packet to the queue
q.setNodePosition(s.getX(),s.getY());
Packet p=(Packet)pe.returnElement();
q.enqueue(p);
}
break;
case PacketEvent.DEQUE: {
Queue q=(Queue)m_queues.get(new Integer(pe.getSource()));
// Queue not enabled for display
if (q==null) break;
Packet p=(Packet)pe.returnElement();
q.dequeue(p);
}
break;
case PacketEvent.HOP: Packet p=(Packet)pe.returnElement();
Node s=(Node)m_nodes.get(new Integer(p.getSource()));
Node d=(Node)m_nodes.get(new Integer(p.getDestination()));
Link l=s.getLink(p.getDestination());
if (l==null) return;
// Calculate the direction the packet is moving
Vector v=new Vector();
v.m_value[0]=d.getX()-s.getX();
v.m_value[1]=d.getY()-s.getY();
// Set all the initial parameters of the packet
p.setStartPosition(s.getX(),s.getY());
p.setDirection(v);
p.setLink(l);
p.setLeaveTime(pe.getTime());
p.setTransmitTime((double)(pe.getSize()*8)/
l.getBandwidth());
double t_time=l.getDelay()+
((double)p.getSize()*8.0)/l.getBandwidth();
p.setArriveTime(pe.getTime()+t_time);
p.readyToGo();
m_elements.addElement(p);
break;
case PacketEvent.DROP: int packetID=pe.getPacketID();
Queue q=(Queue)m_queues.get(new Integer(pe.getSource()));
// Find out if the packet is dropping from a
// queue or from a link..
if (q!=null && q.getQueuedPacket(packetID)!=null) {
Packet dp=q.getQueuedPacket(packetID);
// Dropping from a queue
double endX=(double)q.getEndX();
double endY=(double)q.getEndY();
dp.setDropStart(endX,endY);
dp.setStatus(Packet.PACKET_DROPPED);
q.drop(dp);
m_elements.addElement(dp);
}
else {
Packet dp=null;
// Dropping from a link
for(int i=0; i