From 978de733514afb5cb463e017f3fd78112e293f29 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Tue, 16 Jun 2009 18:01:43 +0000
Subject: [PATCH]     * netdb.jsp: Add country chart at bottom, clean up
 version chart

---
 core/java/src/net/i2p/util/ObjectCounter.java | 42 ++++++++++++
 .../src/net/i2p/router/CommSystemFacade.java  |  1 +
 .../KademliaNetworkDatabaseFacade.java        | 67 +++++++++++--------
 .../transport/CommSystemFacadeImpl.java       | 16 +++--
 .../router/tunnel/pool/TunnelPoolManager.java | 38 +++--------
 5 files changed, 102 insertions(+), 62 deletions(-)
 create mode 100644 core/java/src/net/i2p/util/ObjectCounter.java

diff --git a/core/java/src/net/i2p/util/ObjectCounter.java b/core/java/src/net/i2p/util/ObjectCounter.java
new file mode 100644
index 0000000000..19c92ae666
--- /dev/null
+++ b/core/java/src/net/i2p/util/ObjectCounter.java
@@ -0,0 +1,42 @@
+package net.i2p.util;
+
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ *  Count things.
+ *
+ *  @author zzz
+ */
+public class ObjectCounter<K> {
+    private ConcurrentHashMap<K, Integer> _map;
+    public ObjectCounter() {
+        _map = new ConcurrentHashMap();
+    }
+    /**
+     *  Add one.
+     *  Not perfectly concurrent, new AtomicInteger(1) would be better,
+     *  at the cost of some object churn.
+     */
+    public void increment(K h) {
+        Integer i = _map.putIfAbsent(h, Integer.valueOf(1));
+        if (i != null)
+            _map.put(h, Integer.valueOf(i.intValue() + 1));
+    }
+    /**
+     *  @return current count
+     */
+    public int count(K h) {
+        Integer i = _map.get(h);
+        if (i != null)
+            return i.intValue();
+        return 0;
+    }
+    /**
+     *  @return set of objects with counts > 0
+     */
+    public Set<K> objects() {
+        return _map.keySet();
+    }
+}
+
diff --git a/router/java/src/net/i2p/router/CommSystemFacade.java b/router/java/src/net/i2p/router/CommSystemFacade.java
index 2e85a7eb5f..4fe9147ace 100644
--- a/router/java/src/net/i2p/router/CommSystemFacade.java
+++ b/router/java/src/net/i2p/router/CommSystemFacade.java
@@ -62,6 +62,7 @@ public abstract class CommSystemFacade implements Service {
     public byte[] getIP(Hash dest) { return null; }
     public void queueLookup(byte[] ip) {}
     public String getCountry(Hash peer) { return null; }
+    public String getCountryName(String code) { return code; }
     public String renderPeerHTML(Hash peer) { return null; }
     
     /** 
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
index ae5dd9d803..e61a585541 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
@@ -10,12 +10,15 @@ package net.i2p.router.networkdb.kademlia;
 
 import java.io.IOException;
 import java.io.Writer;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
@@ -42,6 +45,7 @@ import net.i2p.router.networkdb.DatabaseStoreMessageHandler;
 import net.i2p.router.networkdb.PublishLocalRouterInfoJob;
 import net.i2p.router.peermanager.PeerProfile;
 import net.i2p.util.Log;
+import net.i2p.util.ObjectCounter;
 
 /**
  * Kademlia based version of the network database
@@ -1011,8 +1015,8 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
         out.write(buf.toString());
         buf.setLength(0);
         
-        /* coreVersion to Map of routerVersion to Integer */
-        Map versions = new TreeMap();
+        ObjectCounter<String> versions = new ObjectCounter();
+        ObjectCounter<String> countries = new ObjectCounter();
         
         Set routers = new TreeSet(new RouterInfoComparator());
         routers.addAll(getRouters());
@@ -1024,40 +1028,47 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
                 renderRouterInfo(buf, ri, false, full);
                 out.write(buf.toString());
                 buf.setLength(0);
-                String coreVersion = ri.getOption("coreVersion");
                 String routerVersion = ri.getOption("router.version");
-                if ( (coreVersion != null) && (routerVersion != null) ) {
-                    Map routerVersions = (Map)versions.get(coreVersion);
-                    if (routerVersions == null) {
-                        routerVersions = new TreeMap();
-                        versions.put(coreVersion, routerVersions);
-                    }
-                    Integer val = (Integer)routerVersions.get(routerVersion);
-                    if (val == null)
-                        routerVersions.put(routerVersion, Integer.valueOf(1));
-                    else
-                        routerVersions.put(routerVersion, Integer.valueOf(val.intValue() + 1));
-                }
+                if (routerVersion != null)
+                    versions.increment(routerVersion);
+                String country = _context.commSystem().getCountry(key);
+                if(country != null)
+                    countries.increment(country);
             }
         }
             
-        if (versions.size() > 0) {
+        buf.append("<table border=\"0\" cellspacing=\"30\"><tr><td valign=\"top\">");
+        List<String> versionList = new ArrayList(versions.objects());
+        if (versionList.size() > 0) {
+            Collections.sort(versionList, Collections.reverseOrder());
             buf.append("<table border=\"1\">\n");
-            buf.append("<tr><td><b>Core version</b></td><td><b>Router version</b></td><td><b>Number</b></td></tr>\n");
-            for (Iterator iter = versions.entrySet().iterator(); iter.hasNext(); ) {
-                Map.Entry entry = (Map.Entry)iter.next();
-                String coreVersion = (String)entry.getKey();
-                Map routerVersions = (Map)entry.getValue();
-                for (Iterator routerIter = routerVersions.keySet().iterator(); routerIter.hasNext(); ) {
-                    String routerVersion = (String)routerIter.next();
-                    Integer num = (Integer)routerVersions.get(routerVersion);
-                    buf.append("<tr><td>").append(DataHelper.stripHTML(coreVersion));
-                    buf.append("</td><td>").append(DataHelper.stripHTML(routerVersion));
-                    buf.append("</td><td>").append(num.intValue()).append("</td></tr>\n");
-                }
+            buf.append("<tr><th>Version</th><th>Count</th></tr>\n");
+            for (String routerVersion : versionList) {
+                int num = versions.count(routerVersion);
+                buf.append("<tr><td>").append(DataHelper.stripHTML(routerVersion));
+                buf.append("</td><td align=\"right\">").append(num).append("</td></tr>\n");
+            }
+            buf.append("</table>\n");
+        }
+        buf.append("</td><td valign=\"top\">");
+        out.write(buf.toString());
+        buf.setLength(0);
+            
+        List<String> countryList = new ArrayList(countries.objects());
+        if (countryList.size() > 0) {
+            Collections.sort(countryList);
+            buf.append("<table border=\"1\">\n");
+            buf.append("<tr><th>Country</th><th>Count</th></tr>\n");
+            for (String country : countryList) {
+                int num = countries.count(country);
+                buf.append("<tr><td><img alt=\"").append(country.toUpperCase()).append("\"");
+                buf.append(" src=\"/flags.jsp?c=").append(country).append("\"> ");
+                buf.append(_context.commSystem().getCountryName(country));
+                buf.append("</td><td align=\"right\">").append(num).append("</td></tr>\n");
             }
             buf.append("</table>\n");
         }
+        buf.append("</td></tr></table>");
         out.write(buf.toString());
         out.flush();
     }
diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
index a798e0c18d..04d4f8d23b 100644
--- a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
+++ b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
@@ -433,6 +433,16 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
         return props.getProperty("host");
     }
 
+    /** full name for a country code, or the code if we don't know the name */
+    public String getCountryName(String c) {
+        if (_geoIP == null)
+            return c;
+        String n = _geoIP.fullName(c);
+        if (n == null)
+            return c;
+        return n;
+    }
+
     /** Provide a consistent "look" for displaying router IDs in the console */
     public String renderPeerHTML(Hash peer) {
         String h = peer.toBase64().substring(0, 4);
@@ -440,11 +450,7 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
         String c = getCountry(peer);
         if (c != null) {
             buf.append("<img alt=\"").append(c.toUpperCase()).append("\" title=\"");
-            String n = _geoIP.fullName(c);
-            if (n != null)
-                buf.append(n);
-            else
-                buf.append(c);
+            buf.append(getCountryName(c));
             buf.append("\" src=\"/flags.jsp?c=").append(c).append("\"> ");
         }
         buf.append("<tt><font size=\"+1\">");
diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java
index 9845a72f34..7293b6a1ef 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java
@@ -29,6 +29,7 @@ import net.i2p.router.tunnel.HopConfig;
 import net.i2p.stat.RateStat;
 import net.i2p.util.I2PThread;
 import net.i2p.util.Log;
+import net.i2p.util.ObjectCounter;
 
 /**
  * 
@@ -588,15 +589,15 @@ public class TunnelPoolManager implements TunnelManagerFacade {
     
     private void renderPeers(Writer out) throws IOException {
         // count up the peers in the local pools
-        HashCounter lc = new HashCounter();
+        ObjectCounter<Hash> lc = new ObjectCounter();
         int tunnelCount = countTunnelsPerPeer(lc);
 
         // count up the peers in the participating tunnels
-        HashCounter pc = new HashCounter();
+        ObjectCounter<Hash> pc = new ObjectCounter();
         int partCount = countParticipatingPerPeer(pc);
 
-        Set<Hash> peers = new HashSet(lc.hashes());
-        peers.addAll(pc.hashes());
+        Set<Hash> peers = new HashSet(lc.objects());
+        peers.addAll(pc.objects());
         List<Hash> peerList = new ArrayList(peers);
         Collections.sort(peerList, new HashComparator());
 
@@ -625,7 +626,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
     }
 
     /** @return total number of non-fallback expl. + client tunnels */
-    private int countTunnelsPerPeer(HashCounter lc) {
+    private int countTunnelsPerPeer(ObjectCounter<Hash> lc) {
         List<TunnelPool> pools = new ArrayList();
         listPools(pools);
         int tunnelCount = 0;
@@ -661,12 +662,12 @@ public class TunnelPoolManager implements TunnelManagerFacade {
      *  @return Set of peers that should not be allowed in another tunnel
      */
     public Set<Hash> selectPeersInTooManyTunnels() {
-        HashCounter lc = new HashCounter();
+        ObjectCounter<Hash> lc = new ObjectCounter();
         int tunnelCount = countTunnelsPerPeer(lc);
         Set<Hash> rv = new HashSet();
         if (tunnelCount >= 4 && _context.router().getUptime() > 10*60*1000) {
             int max = _context.getProperty("router.maxTunnelPercentage", DEFAULT_MAX_PCT_TUNNELS);
-            for (Hash h : lc.hashes()) {
+            for (Hash h : lc.objects()) {
                  if (lc.count(h) > 0 && (lc.count(h) + 1) * 100 / (tunnelCount + 1) > max)
                      rv.add(h);
             }
@@ -675,7 +676,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
     }
 
     /** @return total number of part. tunnels */
-    private int countParticipatingPerPeer(HashCounter pc) {
+    private int countParticipatingPerPeer(ObjectCounter<Hash> pc) {
         List<HopConfig> participating = _context.tunnelDispatcher().listParticipatingTunnels();
         for (HopConfig cfg : participating) {
             Hash from = cfg.getReceiveFrom();
@@ -694,27 +695,6 @@ public class TunnelPoolManager implements TunnelManagerFacade {
         }
     }
 
-    private static class HashCounter {
-        private ConcurrentHashMap<Hash, Integer> _map;
-        public HashCounter() {
-            _map = new ConcurrentHashMap();
-        }
-        public void increment(Hash h) {
-            Integer i = _map.putIfAbsent(h, Integer.valueOf(1));
-            if (i != null)
-                _map.put(h, Integer.valueOf(i.intValue() + 1));
-        }
-        public int count(Hash h) {
-            Integer i = _map.get(h);
-            if (i != null)
-                return i.intValue();
-            return 0;
-        }
-        public Set<Hash> hashes() {
-            return _map.keySet();
-        }
-    }
-
     private String getCapacity(Hash peer) {
         RouterInfo info = _context.netDb().lookupRouterInfoLocally(peer);
         if (info != null) {
-- 
GitLab