diff --git a/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java index ef81a92d265083086479aaf922a3aeaa902af802..f0e01fc4926dc5d5a021890e0b2cee69d768e85c 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java @@ -89,6 +89,8 @@ public class GraphHelper extends FormHandler { public void setPersistent(String foo) { _persistent = true; } public String getImages() { + if (StatSummarizer.instance().isDisabled()) + return ""; try { List listeners = StatSummarizer.instance().getListeners(); TreeSet ordered = new TreeSet(new AlphaComparator()); @@ -155,6 +157,8 @@ public class GraphHelper extends FormHandler { private static final int[] times = { 60, 2*60, 5*60, 10*60, 30*60, 60*60, -1 }; public String getForm() { + if (StatSummarizer.instance().isDisabled()) + return ""; String prev = System.getProperty("net.i2p.router.web.GraphHelper.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.GraphHelper.noncePrev", prev); String nonce = "" + _context.random().nextLong(); @@ -198,6 +202,27 @@ public class GraphHelper extends FormHandler { return ""; } + /** + * We have to do this here because processForm() isn't called unless the nonces are good + * @since 0.8.6 + */ + @Override + public String getAllMessages() { + if (StatSummarizer.instance().isDisabled()) { + addFormError("Graphing not supported with this JVM: " + + System.getProperty("java.vendor") + ' ' + + System.getProperty("java.version") + " (" + + System.getProperty("java.runtime.name") + ' ' + + System.getProperty("java.runtime.version") + ')'); + if (_context.getProperty(PROP_REFRESH, 0) >= 0) { + // force no refresh, save silently + _context.router().setConfigSetting(PROP_REFRESH, "-1"); + _context.router().saveConfig(); + } + } + return super.getAllMessages(); + } + /** * This was a HelperBase but now it's a FormHandler * @since 0.8.2 diff --git a/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java index 431696296eaee99d0c4799ede6c1dc2ea82a9dde..26e5f246394417d053f3f974701d9698ad82b6e7 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java @@ -48,6 +48,7 @@ public class StatSummarizer implements Runnable { private static final int MAX_CONCURRENT_PNG = 3; private final Semaphore _sem; private volatile boolean _isRunning = true; + private volatile boolean _isDisabled; private Thread _thread; public StatSummarizer() { @@ -62,6 +63,20 @@ public class StatSummarizer implements Runnable { public static StatSummarizer instance() { return _instance; } public void run() { + // JRobin 1.5.9 crashes these JVMs + String vendor = System.getProperty("java.vendor"); + if (vendor.startsWith("Apache") || // Harmony + vendor.startsWith("GNU Classpath") || // JamVM + vendor.startsWith("Free Software Foundation")) { // gij + _log.logAlways(Log.WARN, "Graphing not supported with this JVM: " + + vendor + ' ' + + System.getProperty("java.version") + " (" + + System.getProperty("java.runtime.name") + ' ' + + System.getProperty("java.runtime.version") + ')'); + _isDisabled = true; + _isRunning = false; + return; + } boolean isPersistent = _context.getBooleanPropertyDefaultTrue(SummaryListener.PROP_PERSISTENT); if (!isPersistent) deleteOldRRDs(); @@ -73,6 +88,11 @@ public class StatSummarizer implements Runnable { } } + /** @since 0.8.6 */ + boolean isDisabled() { + return _isDisabled; + } + /** list of SummaryListener instances */ List<SummaryListener> getListeners() { return _listeners; } @@ -142,8 +162,11 @@ public class StatSummarizer implements Runnable { } private void addDb(Rate r) { SummaryListener lsnr = new SummaryListener(r); - _listeners.add(lsnr); - lsnr.startListening(); + boolean success = lsnr.startListening(); + if (success) + _listeners.add(lsnr); + else + _log.error("Failed to add RRD for rate " + r.getRateStat().getName() + '.' + r.getPeriod()); //System.out.println("Start listening for " + r.getRateStat().getName() + ": " + r.getPeriod()); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java index b5721ff5fe0f8f0933ec66c0b3338b6dc0003210..3b48833c7f9032e7e7543e63e0c8deb5a3880f29 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java @@ -104,7 +104,10 @@ class SummaryListener implements RateSummaryListener { public Rate getRate() { return _rate; } - public void startListening() { + /** + * @return success + */ + public boolean startListening() { RateStat rs = _rate.getRateStat(); long period = _rate.getPeriod(); String baseName = rs.getName() + "." + period; @@ -156,11 +159,15 @@ class SummaryListener implements RateSummaryListener { _sample = _db.createSample(); _renderer = new SummaryRenderer(_context, this); _rate.setSummaryListener(this); + return true; + } catch (OutOfMemoryError oom) { + _log.error("Error starting RRD for stat " + baseName, oom); } catch (RrdException re) { - _log.error("Error starting", re); + _log.error("Error starting RRD for stat " + baseName, re); } catch (IOException ioe) { - _log.error("Error starting", ioe); + _log.error("Error starting RRD for stat " + baseName, ioe); } + return false; } public void stopListening() { @@ -181,10 +188,16 @@ class SummaryListener implements RateSummaryListener { } public void renderPng(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, boolean showCredit) throws IOException { + if (_renderer == null || _db == null) + throw new IOException("No RRD, check logs for previous errors"); _renderer.render(out, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, showCredit); } - public void renderPng(OutputStream out) throws IOException { _renderer.render(out); } + public void renderPng(OutputStream out) throws IOException { + if (_renderer == null || _db == null) + throw new IOException("No RRD, check logs for previous errors"); + _renderer.render(out); + } String getName() { return _name; }