se.sics.gvod.web.server.VodMonitorServer.java Source code

Java tutorial

Introduction

Here is the source code for se.sics.gvod.web.server.VodMonitorServer.java

Source

/**
 * This file is part of the Kompics P2P Framework.
 * 
 * Copyright (C) 2009 Swedish Institute of Computer Science (SICS)
 * Copyright (C) 2009 Royal Institute of Technology (KTH)
 *
 * Kompics 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 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package se.sics.gvod.web.server;

import se.sics.gvod.common.msgs.DownloadCompleted;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;
import se.sics.gvod.timer.TimeoutId;

import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import se.sics.kompics.ComponentDefinition;
import se.sics.kompics.Handler;
import se.sics.kompics.Negative;
import se.sics.kompics.Positive;
import se.sics.gvod.timer.CancelTimeout;
import se.sics.gvod.timer.ScheduleTimeout;
import se.sics.gvod.timer.Timer;
import se.sics.kompics.web.Web;
import se.sics.kompics.web.WebRequest;
import se.sics.kompics.web.WebResponse;
import se.sics.gvod.common.VodNeighbors;
import se.sics.gvod.net.VodAddress;
import se.sics.gvod.common.VodDescriptor;
//import se.sics.gvod.common.GraphUtil;
import org.apache.commons.math.stat.descriptive.SummaryStatistics;
import se.sics.gvod.net.VodNetwork;

/**
 * The <code>GVodMonitorServer</code> class.
 * 
 * @author Cosmin Arad <cosmin@sics.se>
 * @version $Id: GVodMonitorServer.java 1218 2009-09-06 21:31:02Z Cosmin $
 */
public class VodMonitorServer extends ComponentDefinition {

    Positive<VodNetwork> network = positive(VodNetwork.class);
    Positive<Timer> timer = positive(Timer.class);
    Negative<Web> web = negative(Web.class);
    private static final Logger logger = LoggerFactory.getLogger(VodMonitorServer.class);
    // private long updatePeriod;
    private final HashSet<TimeoutId> outstandingTimeouts;
    private final HashMap<VodAddress, OverlayViewEntry> view;
    private TreeMap<VodAddress, VodNeighbors> alivePeers;
    private TreeMap<VodAddress, VodNeighbors> deadPeers;
    private long evictAfter;
    private int webPort;
    private SummaryStatistics downloadTime;
    private int nbOfFinish = 0;

    public VodMonitorServer() {
        this.view = new HashMap<VodAddress, OverlayViewEntry>();
        this.alivePeers = new TreeMap<VodAddress, VodNeighbors>();
        this.deadPeers = new TreeMap<VodAddress, VodNeighbors>();
        this.outstandingTimeouts = new HashSet<TimeoutId>();
        this.downloadTime = new SummaryStatistics();

        subscribe(handleInit, control);

        subscribe(handleWebRequest, web);
        subscribe(handlePeerNotification, network);
        subscribe(handleDownloadCompleted, network);
        subscribe(handleViewEvictPeer, timer);
    }

    private Handler<VodMonitorServerInit> handleInit = new Handler<VodMonitorServerInit>() {

        public void handle(VodMonitorServerInit event) {
            evictAfter = event.getConfiguration().getViewEvictAfter();
            webPort = event.getConfiguration().getClientWebPort();
            logger.debug("INIT");

            try {
                UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
            } catch (ClassNotFoundException e1) {
                e1.printStackTrace();
            } catch (InstantiationException e1) {
                e1.printStackTrace();
            } catch (IllegalAccessException e1) {
                e1.printStackTrace();
            } catch (UnsupportedLookAndFeelException e1) {
                e1.printStackTrace();
            }
        }
    };
    private Handler<VodNeighborsNotification> handlePeerNotification = new Handler<VodNeighborsNotification>() {

        public void handle(VodNeighborsNotification event) {
            VodAddress peerAddress = event.getPeerAddress();
            VodNeighbors neighbors = event.getGVodNeighbors();
            VodAddress vodAddress = neighbors.getSelf();

            addPeerToView(vodAddress, neighbors, event.getUtility());

            logger.debug("Got notification from peer {}", peerAddress);
        }
    };
    Handler<DownloadCompleted> handleDownloadCompleted = new Handler<DownloadCompleted>() {

        public void handle(DownloadCompleted event) {
            logger.debug("Peer {} completed watching.", event.getSource());
            //            Integer peerId = event.getSource().getId();
            downloadTime.addValue(event.getDownloadTime());
            nbOfFinish++;
        }
    };
    private Handler<ViewEvictPeer> handleViewEvictPeer = new Handler<ViewEvictPeer>() {

        public void handle(ViewEvictPeer event) {
            // only evict if it was not refreshed in the meantime
            // which means the timer is not anymore outstanding
            if (outstandingTimeouts.contains(event.getTimeoutId())) {
                removePeerFromView(event.getOverlayAddress());
            }
        }
    };
    private Handler<WebRequest> handleWebRequest = new Handler<WebRequest>() {

        public void handle(WebRequest event) {
            logger.debug("Handling WebRequest");

            String peers = event.getRequest().getParameter("peers");

            boolean showPeers = peers == null ? false : peers.equals("on") ? true : false;

            String html = dumpViewToHtml(showPeers);
            WebResponse response = new WebResponse(html, event, 1, 1);
            trigger(response, web);
        }
    };

    private void addPeerToView(VodAddress address, VodNeighbors neighbors, int utility) {
        long now = System.currentTimeMillis();

        alivePeers.put(address, neighbors);
        deadPeers.remove(address);

        OverlayViewEntry entry = view.get(address);
        if (entry == null) {
            entry = new OverlayViewEntry(address, now, now, utility);
            view.put(address, entry);

            // set eviction timer
            ScheduleTimeout st = new ScheduleTimeout(evictAfter);
            st.setTimeoutEvent(new ViewEvictPeer(st, address));
            TimeoutId evictionTimerId = st.getTimeoutEvent().getTimeoutId();
            entry.setEvictionTimerId(evictionTimerId);
            outstandingTimeouts.add(evictionTimerId);

            trigger(st, timer);

            logger.debug("Added peer {}", address);
        } else {
            entry.setRefreshedAt(now);
            entry.setUtility(utility);
            // reset eviction timer
            outstandingTimeouts.remove(entry.getEvictionTimerId());
            trigger(new CancelTimeout(entry.getEvictionTimerId()), timer);

            ScheduleTimeout st = new ScheduleTimeout(evictAfter);
            st.setTimeoutEvent(new ViewEvictPeer(st, address));
            TimeoutId evictionTimerId = st.getTimeoutEvent().getTimeoutId();
            entry.setEvictionTimerId(evictionTimerId);
            outstandingTimeouts.add(evictionTimerId);

            trigger(st, timer);

            logger.debug("Refreshed peer {}, utility {}", address, utility);
        }
    }

    private void removePeerFromView(VodAddress address) {
        if (address != null) {
            VodNeighbors neighbors = alivePeers.remove(address);
            deadPeers.put(address, neighbors);
            logger.debug("Removed peer {}", address);
        }
    }

    private String dumpViewToHtml(boolean showPeers) {
        StringBuilder sb = new StringBuilder("<!DOCTYPE html PUBLIC ");
        sb.append("\"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3");
        sb.append(".org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=");
        sb.append("\"http://www.w3.org/1999/xhtml\"><head><meta http-equiv=\"");
        sb.append("Content-Type\" content=\"text/html; charset=utf-8\" />");

        // page refresh
        // sb.append("<meta http-equiv=\"refresh\" content=\"10\">");
        sb.append("<title>Kompics P2P Monitor Server</title>");
        sb.append("<style type=\"text/css\"><!--.style2 {font-family: ");
        sb.append("Arial, Helvetica, sans-serif; color: #0099FF;}--></style>");
        sb.append("</head><body><h1 align=\"center\" class=\"style2\">");
        sb.append("Kompics P2P Monitor</h1>");

        //        printAlivePeers(sb, showPeers);
        if (showPeers) {
            printDeadPeers(sb);
        }
        sb.append("</body></html>");
        return sb.toString();
    }

    /*
    private void printAlivePeers(StringBuilder sb, boolean showPeers) {
        
    long t0 = System.currentTimeMillis();
    long t1 = System.currentTimeMillis();
        
    double id, od, cc, pl, istd;
    int diameter;
        
    id = g.getMeanInDegree();
    istd = g.getInDegreeStdDev();
    od = g.getMeanOutDegree();
    cc = g.getMeanClusteringCoefficient();
    pl = g.getMeanPathLength();
    diameter = g.getDiameter();
    int netSize = g.getNetworkSize();
        
    sb.append("<h2 align=\"center\" class=\"style2\">");
    sb.append("View of GVod Random Overlay:</h2>");
    sb.append("<table width=\"400\" border=\"1\" align=\"center\"><tr>");
    sb.append("<th class=\"style2\" width=\"250\" scope=\"col\">Metric");
    sb.append("</th><th class=\"style2\"");
    sb.append(" width=\"150\" scope=\"col\">Value</th></tr><tr>");
        
    sb.append("<td>Network size</td><td><div align=\"center\">");
    sb.append(netSize).append("</div></td></tr>");
    sb.append("<td>Disconnected node pairs</td><td><div align=\"center\">");
    sb.append(g.getInfinitePathCount()).append("/");
    sb.append(netSize * (netSize - 1)).append("</div></td></tr>");
    sb.append("<td>Diameter</td><td><div align=\"center\">");
    sb.append(diameter).append("</div></td></tr>");
    sb.append("<td>Average path length</td><td><div align=\"center\">");
    sb.append(String.format("%.4f", pl)).append("</div></td></tr>");
    sb.append("<td>Clustering-coefficient</td><td><div align=\"center\">");
    sb.append(String.format("%.4f", cc)).append("</div></td></tr>");
    sb.append("<td>Average in-degree</td><td><div align=\"center\">");
    sb.append(String.format("%.4f", id)).append("</div></td></tr>");
    sb.append("<td>In-degree standard deviation</td><td><div align=\"center\">");
    sb.append(String.format("%.4f", istd)).append("</div></td></tr>");
    sb.append("<td>Average out-degree</td><td><div align=\"center\">");
    sb.append(String.format("%.4f", od)).append("</div></td></tr>");
    sb.append("<td>Average changes in utilitySet per cycle</td><td><div align=\"center\">");
    sb.append(String.format("%.4f", g.getAvgUtilitySetNbChange())).append("</div></td></tr>");
    sb.append("<td>Average changes in upperSet per cycle</td><td><div align=\"center\">");
    sb.append(String.format("%.4f", g.getAvgUtilitySetNbChange())).append("</div></td></tr>");
    sb.append("<td>Average time to download the movie</td><td><div align=\"center\">");
    sb.append(String.format("%.1f", downloadTime.getMean())).append("</div></td></tr>");
    sb.append("<td>Max time to download the movie</td><td><div align=\"center\">");
    sb.append(String.format("%.0f", downloadTime.getMax())).append("</div></td></tr>");
    sb.append("<td>Min time to download the movie</td><td><div align=\"center\">");
    sb.append(String.format("%.0f", downloadTime.getMin())).append("</div></td></tr>");
    sb.append("<td>number of download</td><td><div align=\"center\">");
    sb.append(String.format("%d", nbOfFinish)).append("</div></td></tr>");
    sb.append("</table>");
        
    // print in-degree distribution
    HistogramDataset dataset = new HistogramDataset();
    double[] values = g.getInDegrees();
    int min = (int) g.getMinInDegree(), max = (int) g.getMaxInDegree();
    int bins = max - min;
    bins = bins < 1 ? 1 : bins;
    dataset.addSeries("In-degree distribution", values, bins, min, max);
    JFreeChart chart = ChartFactory.createHistogram(null, null, null,
            dataset, PlotOrientation.VERTICAL, true, false, false);
    // chart.getXYPlot().setForegroundAlpha(0.95f);
    //        BufferedImage image = chart.createBufferedImage(800, 300);
    //
    //        String imageString = "";
    //        try {
    //            ByteArrayOutputStream out = new ByteArrayOutputStream();
    //            ImageIO.write(image, "png", out);
    //            out.close();
    //            BASE64Encoder bencoder = new BASE64Encoder();
    //            imageString = bencoder.encode(out.toByteArray());
    //            imageString = "data:image/png;base64," + imageString;
    //        } catch (IOException e) {
    //            sb.append(e);
    //        }
        
    //        sb.append("<br><div align=\"center\"><img src=\"").append(imageString);
    //        sb.append("\" alt=\"In-degree distribution " + "\" /></div><br>");
        
    sb.append("<div align=\"center\">It took ").append(t1 - t0);
    sb.append("ms to compute these statistics.<br>");
        
    // refresh form
    sb.append("<form method=\"get\" name=\"rfrshFrm\" id=\"rfrshFrm\">");
    sb.append("<label>Show peers ");
    sb.append("<input name=\"peers\" type=\"checkbox\" id=\"peers\" />");
    //sb.append("checked=\"").append("false").append("\" />");
    sb.append("<input type=\"submit\" value=\"Refresh\" />");
    sb.append("</form></div>");
        
    if (!showPeers) {
        return;
    }
        
    sb.append("<h2 align=\"center\" class=\"style2\">");
    sb.append("Individual peers:</h2>");
    sb.append("<table width=\"1300\" border=\"1\" align=\"center\"><tr>");
    sb.append("<th class=\"style2\" width=\"50\" scope=\"col\">Count</th>");
    sb.append("<th class=\"style2\" width=\"50\" scope=\"col\">Peer</th>");
    sb.append("<th class=\"style2\" width=\"800\" scope=\"col\">Neighbors</th>");
    sb.append("<th class=\"style2\" width=\"50\" scope=\"col\">In Degree</th>");
    sb.append("<th class=\"style2\" width=\"50\" scope=\"col\">Out Degree</th>");
    sb.append("<th class=\"style2\" width=\"100\" scope=\"col\">Cluestering Coefficient</th>");
    sb.append("<th class=\"style2\" width=\"50\" scope=\"col\">Age</th>");
    sb.append("<th class=\"style2\" width=\"100\" scope=\"col\">Freshness</th>");
    sb.append("<th class=\"style2\" width=\"100\" scope=\"col\">Utility</th></tr>");
        
    int count = 1;
        
    for (VodAddress address : alivePeers.keySet()) {
        VodNeighbors neighbors = alivePeers.get(address);
        
        List<VodDescriptor> descriptors = neighbors.getDescriptors();
        Collections.sort(descriptors);
        
        sb.append("<tr>");
        sb.append("<td><div align=\"center\">").append(count++);
        //sb.append("(").append(g.map.get(address)).append(")");
        sb.append("</div></td>");
        
        // print peer address
        sb.append("</div></td><td bgcolor=\"#99CCFF\"><div align=\"center\">");
        appendPeerLink(sb, address);
        sb.append("</div></td>");
        
        // print neighbors
        if (descriptors != null) {
            sb.append("<td><div align=\"left\">");
            sb.append("[");
            Iterator<VodDescriptor> iter = descriptors.iterator();
            while (iter.hasNext()) {
                appendPeerLink(sb, iter.next().getVodAddress());
                if (iter.hasNext()) {
                    sb.append(", ");
                }
            }
            sb.append("]");
        } else {
            sb.append("<td bgcolor=\"#FFCCFF\"><div align=\"left\">");
            sb.append("[empty]");
        }
        sb.append("</div></td>");
        
        int v = g.getNodeIndexByAddress(address);
        
        // print in-degree
        sb.append("<td><div align=\"center\">").append(g.getInDegree(v));
        sb.append("</div></td>");
        // print out-degree
        sb.append("<td><div align=\"center\">").append(g.getOutDegree(v));
        sb.append("</div></td>");
        // print clustering coefficient
        
        // directedGraph
        
        sb.append("<td><div align=\"center\">").append(
                String.format("%.4f", g.getClustering(v)));
        sb.append("</div></td>");
        
        long now = System.currentTimeMillis();
        OverlayViewEntry viewEntry = view.get(address);
        
        // print age
        sb.append("<td><div align=\"right\">");
        sb.append(durationToString(now - viewEntry.getAddedAt()));
        sb.append("</div></td>");
        
        // print freshness
        sb.append("<td><div align=\"right\">");
        sb.append(durationToString(now - viewEntry.getRefreshedAt()));
        sb.append("</div></td>");
        
        // print utility
        sb.append("<td><div align=\"right\">");
        sb.append(viewEntry.getUtility());
        sb.append("</div></td>");
        
        sb.append("</tr>");
    }
    sb.append("</table>");
    }
    */
    private void printDeadPeers(StringBuilder sb) {
        int count;
        // print dead peers
        if (deadPeers.size() > 0) {
            sb.append("<h2 align=\"center\" class=\"style2\">");
            sb.append("Dead peers:</h2>");
            sb.append("<table width=\"1300\" border=\"1\" align=\"center\"><tr>");
            sb.append("<th class=\"style2\" width=\"50\" scope=\"col\">Count</th>");
            sb.append("<th class=\"style2\" width=\"50\" scope=\"col\">Peer</th>");
            sb.append("<th class=\"style2\" width=\"800\" scope=\"col\">Neighbors</th>");
            sb.append("<th class=\"style2\" width=\"50\" scope=\"col\">In Degree</th>");
            sb.append("<th class=\"style2\" width=\"50\" scope=\"col\">Out Degree</th>");
            sb.append("<th class=\"style2\" width=\"100\" scope=\"col\">Cluestering Coefficient</th>");

            sb.append("<th class=\"style2\" width=\"50\" scope=\"col\">Lifetime</th>");
            sb.append("<th class=\"style2\" width=\"100\" scope=\"col\">Dead for</th></tr>");

            LinkedList<VodAddress> peers = new LinkedList<VodAddress>(deadPeers.descendingKeySet());

            count = 1;

            for (VodAddress address : peers) {
                VodNeighbors neighbors = deadPeers.get(address);

                List<VodDescriptor> descriptors = neighbors.getDescriptors();

                sb.append("<tr>");
                sb.append("<td><div align=\"center\">").append(count++);
                // sb.append("(").append(g.map.get(address)).append(")");
                sb.append("</div></td>");

                // print peer address
                sb.append("</div></td><td bgcolor=\"#99CCFF\"><div align=\"center\">");
                appendPeerLink(sb, address);
                sb.append("</div></td>");

                // print neighbors
                if (descriptors != null) {
                    sb.append("<td><div align=\"left\">");
                    sb.append("[");
                    Iterator<VodDescriptor> iter = descriptors.iterator();
                    while (iter.hasNext()) {
                        appendPeerLink(sb, iter.next().getVodAddress());
                        if (iter.hasNext()) {
                            sb.append(", ");
                        }
                    }
                    sb.append("]");
                } else {
                    sb.append("<td bgcolor=\"#FFCCFF\"><div align=\"left\">");
                    sb.append("[empty]");
                }
                sb.append("</div></td>");

                // print in-degree
                sb.append("<td><div align=\"center\">").append(0);
                sb.append("</div></td>");
                // print out-degree
                sb.append("<td><div align=\"center\">").append(0);
                sb.append("</div></td>");
                // print clustering coefficient

                // directedGraph

                sb.append("<td><div align=\"center\">").append(String.format("%.4f", 0.0));
                sb.append("</div></td>");

                long now = System.currentTimeMillis();
                OverlayViewEntry viewEntry = view.get(address);

                // print lifetime
                sb.append("<td><div align=\"right\">");
                sb.append(durationToString(viewEntry.getRefreshedAt() - viewEntry.getAddedAt()));
                sb.append("</div></td>");

                // print dead for
                sb.append("<td><div align=\"right\">");
                sb.append(durationToString(now - viewEntry.getRefreshedAt()));
                sb.append("</div></td>");

                sb.append("</tr>");
            }
            sb.append("</table>");
        }
    }

    private final void appendPeerLink(StringBuilder sb, VodAddress address) {
        sb.append("<a href=\"http://");
        sb.append(address.getPeerAddress().getIp().getHostAddress());
        sb.append(":").append(address.getPeerAddress().getPort() - 1).append("/");
        //     sb.append(":").append(webPort).append("/");
        sb.append(address.getPeerAddress().getId()).append("/").append("\">");
        // show dead peer links in red
        if (deadPeers.containsKey(address)) {
            sb.append("<FONT style=\"BACKGROUND-COLOR: #FAAFBA\">");
            sb.append(address.toString()).append("</FONT></a>");
        } else {
            sb.append(address.toString()).append("</a>");
        }

    }

    private String durationToString(long duration) {
        StringBuilder sb = new StringBuilder();

        // get duration in seconds
        duration /= 1000;

        int s = 0, m = 0, h = 0, d = 0, y = 0;
        s = (int) (duration % 60);
        // get duration in minutes
        duration /= 60;
        if (duration > 0) {
            m = (int) (duration % 60);
            // get duration in hours
            duration /= 60;
            if (duration > 0) {
                h = (int) (duration % 24);
                // get duration in days
                duration /= 24;
                if (duration > 0) {
                    d = (int) (duration % 365);
                    // get duration in years
                    y = (int) (duration / 365);
                }
            }
        }

        boolean printed = false;

        if (y > 0) {
            sb.append(y).append("y");
            printed = true;
        }
        if (d > 0) {
            sb.append(d).append("d");
            printed = true;
        }
        if (h > 0) {
            sb.append(h).append("h");
            printed = true;
        }
        if (m > 0) {
            sb.append(m).append("m");
            printed = true;
        }
        if (s > 0 || printed == false) {
            sb.append(s).append("s");
        }

        return sb.toString();
    }
}