package thaw.plugins.indexWebGrapher; import java.sql.*; import java.util.Iterator; import java.util.Vector; import thaw.plugins.IndexWebGrapher; import thaw.plugins.Hsqldb; import thaw.fcp.FreenetURIHelper; import thaw.core.Logger; import thaw.core.ThawThread; import thaw.core.ThawRunnable; public class GraphBuilder implements ThawRunnable { private IndexWebGrapher plugin; private GraphPanel graphPanel; private Hsqldb db; private boolean faster; private boolean finish; private boolean stop; public GraphBuilder(IndexWebGrapher plugin, GraphPanel panel, Hsqldb db) { this.plugin = plugin; this.graphPanel = panel; this.db = db; this.faster = false; this.finish = false; this.stop = false; } private class Refresher implements ThawRunnable { public Refresher() { } public void run() { run(true); } public void run(boolean loop) { do { graphPanel.recomputeMinMax(); graphPanel.refresh(); try { Thread.sleep(50); } catch(InterruptedException e) { /* \_o< */ } } while (loop && !stop && !finish); } public void stop() { /* \_o< */ } } public void run() { Logger.info(this, "=== Starting ==="); /* === */ plugin.setProgress(0); Logger.info(this, "0) Loading all the nodes ..."); graphPanel.reinit(); try { synchronized(db.dbLock) { PreparedStatement st; st = db.getConnection().prepareStatement("SELECT id, displayName, publicKey "+ "FROM indexes"); ResultSet set = st.executeQuery(); int nmb = 0; while(set.next()) { String key = set.getString("publicKey"); if (FreenetURIHelper.isObsolete(key)) continue; /* will register itself in the graphPanel */ new Node(nmb, set.getInt("id") /* index id */, set.getString("displayName"), key, graphPanel); nmb++; } st.close(); Logger.info(this, Integer.toString(nmb)+" nodes loaded"); } } catch(SQLException e) { Logger.error(this, "Can't load the nodes because : "+e.toString()); return; } /* === */ plugin.setProgress(1); Logger.info(this, "1) Loading links ..."); try { synchronized(db.dbLock) { PreparedStatement st; st = db.getConnection().prepareStatement("SELECT publicKey FROM links WHERE indexParent = ?"); for (Iterator it = (new Vector(graphPanel.getNodeList())).iterator(); it.hasNext(); ) { Node node = (Node)it.next(); st.setInt(1, node.getIndexId()); ResultSet set = st.executeQuery(); while(set.next()) { String lnk = set.getString("publicKey"); if (FreenetURIHelper.isObsolete(lnk)) continue; Node target = graphPanel.getNode(lnk); if (target == null) { target = new Node(graphPanel.getLastUsedId()+1, -1 /* indexId */, FreenetURIHelper.getFilenameFromKey(lnk).replaceAll(".frdx", ""), lnk, graphPanel); } node.setLinkTo(target); } } st.close(); } } catch(SQLException e) { Logger.error(this, "Can't load the links because : "+e.toString()); return; } /* === */ plugin.setProgress(2); Logger.info(this, "2) Sorting the nodes according to their number of links ..."); Vector nodes = new Vector(graphPanel.getNodeList()); java.util.Collections.sort(nodes); /* === */ plugin.setProgress(3); Logger.info(this, "3) Initial placing of the nodes ..."); double x = 0.0; for (Iterator it = nodes.iterator(); it.hasNext();) { Node node = (Node)it.next(); if (!node.isPositionSet()) { node.setPosition(x, 0.0); node.setInitialNeightbourPositions(); x += ((Node.FACTOR_INITIAL_DISTANCE * node.getLinkCount())+1); } } graphPanel.guessZoom(); graphPanel.recomputeMinMax(); graphPanel.refresh(); try { Thread.sleep(3000); } catch(InterruptedException e) { /* \_o< */ } /* === */ plugin.setProgress(4); Logger.info(this, "4) Optimizing placement ..."); Refresher refresher = new Refresher(); Thread refresherTh = null; int lastStep = 4; double totalKinetic = 0.0; double sumKinetics = 0.0; int nmbKinetics = 0; for (int i = 0 ; i < Node.NMB_STEPS && !stop ; i++) { int currentStep = (6 * i) / Node.NMB_STEPS; if (currentStep != lastStep) { plugin.setProgress(currentStep+4); lastStep = currentStep; } if (i == 0) graphPanel.guessZoom(); if (!faster) refresher.run(false); else { if (refresherTh == null) { refresherTh = new ThawThread(refresher, "Index web display refresh", this); refresherTh.start(); } } if (i != 0) { sumKinetics += totalKinetic; nmbKinetics++; } if (i != 0 && i%100 == 0) { Logger.info(this, "================================"); Logger.info(this, "- Step "+Integer.toString(i)+"/"+Node.NMB_STEPS); Logger.info(this, "- Kinetic : "+Double.toString(totalKinetic)); Logger.info(this, "- Average kinetic : "+Double.toString(sumKinetics/nmbKinetics)); } totalKinetic = 0.0; for (Iterator it = nodes.iterator(); it.hasNext();) { Node node = (Node)it.next(); totalKinetic += node.computeVelocity(nodes); } if (totalKinetic < (Node.MIN_KINETIC)) { Logger.info(this, "Wow, seems optimized :)"); break; } boolean move = false; for (Iterator it = nodes.iterator(); it.hasNext();) { Node node = (Node)it.next(); move |= node.applyVelocity(); } if (!move) { Logger.info(this, "Wow, fully optimized ?!"); break; } } /* === */ plugin.setProgress(9); Logger.info(this, "Drawing ..."); graphPanel.refresh(); /* === */ plugin.setProgress(10); Logger.info(this, "== Pouf, done =="); for (Iterator it = nodes.iterator(); it.hasNext();) { Node node = (Node)it.next(); Logger.info(this, node.toString()); } finish = true; plugin.endOfProcess(); } /* /run */ public void setFasterFlag(boolean faster) { this.faster = faster; } public boolean fasterFlag() { return faster; } public void stop() { stop = true; } public boolean isFinished() { return finish; } }