From 5d6d27907dc89bd183db003513d9d90892281575 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Sun, 14 Oct 2012 13:54:08 +0000
Subject: [PATCH]  * Console: Use non-nio connector for Java 5 and JamVM/gij   
          (tickets #715 and #743)  * SystemVersion: Centralize more methods
 here

---
 .../i2p/router/web/RouterConsoleRunner.java   | 50 +++++++++++++++----
 .../net/i2p/router/web/StatSummarizer.java    |  8 ++-
 core/java/src/net/i2p/crypto/SHA1.java        |  8 +--
 .../net/i2p/util/ReusableGZIPInputStream.java |  2 +-
 .../i2p/util/ReusableGZIPOutputStream.java    |  2 +-
 core/java/src/net/i2p/util/SystemVersion.java | 27 +++++++++-
 installer/resources/eepsite/jetty.xml         |  4 +-
 7 files changed, 76 insertions(+), 25 deletions(-)

diff --git a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java
index e361df3ebb..488c5b655d 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java
@@ -34,11 +34,14 @@ import net.i2p.util.PortMapper;
 import net.i2p.util.SecureDirectory;
 import net.i2p.util.SecureFileOutputStream;
 import net.i2p.util.ShellCommand;
+import net.i2p.util.SystemVersion;
 import net.i2p.util.VersionComparator;
 
+import org.mortbay.jetty.AbstractConnector;
 import org.mortbay.jetty.Connector;
 import org.mortbay.jetty.NCSARequestLog;
 import org.mortbay.jetty.Server;
+import org.mortbay.jetty.bio.SocketConnector;
 import org.mortbay.jetty.handler.ContextHandlerCollection;
 import org.mortbay.jetty.handler.DefaultHandler;
 import org.mortbay.jetty.handler.HandlerCollection;
@@ -49,6 +52,7 @@ import org.mortbay.jetty.security.HashUserRealm;
 import org.mortbay.jetty.security.Constraint;
 import org.mortbay.jetty.security.ConstraintMapping;
 import org.mortbay.jetty.security.SecurityHandler;
+import org.mortbay.jetty.security.SslSocketConnector;
 import org.mortbay.jetty.security.SslSelectChannelConnector;
 import org.mortbay.jetty.servlet.ServletHandler;
 import org.mortbay.jetty.servlet.ServletHolder;
@@ -177,8 +181,7 @@ public class RouterConsoleRunner {
         try {
             //TODO: move away from routerconsole into a separate application.
             //ApplicationManager?
-            VersionComparator v = new VersionComparator();
-            boolean recentJava = v.compare(System.getProperty("java.runtime.version"), "1.6") >= 0;
+            boolean recentJava = SystemVersion.isJava6();
             // default false for now
             boolean desktopguiEnabled = I2PAppContext.getGlobalContext().getBooleanProperty("desktopgui.enabled");
             if (recentJava && desktopguiEnabled) {
@@ -334,12 +337,22 @@ public class RouterConsoleRunner {
                         //    _server.addListener('[' + host + "]:" + _listenPort);
                         //else
                         //    _server.addListener(host + ':' + _listenPort);
-                        SelectChannelConnector lsnr = new SelectChannelConnector();
+                        AbstractConnector lsnr;
+                        if (SystemVersion.isJava6() && !SystemVersion.isGNU()) {
+                            SelectChannelConnector slsnr = new SelectChannelConnector();
+                            slsnr.setUseDirectBuffers(false);  // default true seems to be leaky
+                            lsnr = slsnr;
+                        } else {
+                            // Jetty 6 and NIO on Java 5 don't get along that well
+                            // Also: http://jira.codehaus.org/browse/JETTY-1238
+                            // "Do not use GCJ with Jetty, it will not work."
+                            // Actually it does if you don't use NIO
+                            lsnr = new SocketConnector();
+                        }
                         lsnr.setHost(host);
                         lsnr.setPort(lport);
                         lsnr.setMaxIdleTime(90*1000);  // default 10 sec
                         lsnr.setName("ConsoleSocket");   // all with same name will use the same thread pool
-                        lsnr.setUseDirectBuffers(false);  // default true seems to be leaky
                         //_server.addConnector(lsnr);
                         connectors.add(lsnr);
                         boundAddresses++;
@@ -389,22 +402,37 @@ public class RouterConsoleRunner {
                             }
                             // TODO if class not found use SslChannelConnector
                             // Sadly there's no common base class with the ssl methods in it
-                            SslSelectChannelConnector ssll = new SslSelectChannelConnector();
-                            ssll.setHost(host);
-                            ssll.setPort(sslPort);
+                            AbstractConnector ssll;
+                            if (SystemVersion.isJava6() && !SystemVersion.isGNU()) {
+                                SslSelectChannelConnector sssll = new SslSelectChannelConnector();
+                                // the keystore path and password
+                                sssll.setKeystore(keyStore.getAbsolutePath());
+                                sssll.setPassword(ctx.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
+                                // the X.509 cert password (if not present, verifyKeyStore() returned false)
+                                sssll.setKeyPassword(ctx.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
+                                sssll.setUseDirectBuffers(false);  // default true seems to be leaky
+                                ssll = sssll;
+                            } else {
+                                // Jetty 6 and NIO on Java 5 don't get along that well
+                                SslSocketConnector sssll = new SslSocketConnector();
                             // the keystore path and password
-                            ssll.setKeystore(keyStore.getAbsolutePath());
-                            ssll.setPassword(ctx.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
+                                sssll.setKeystore(keyStore.getAbsolutePath());
+                                sssll.setPassword(ctx.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
                             // the X.509 cert password (if not present, verifyKeyStore() returned false)
-                            ssll.setKeyPassword(ctx.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
+                                sssll.setKeyPassword(ctx.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
+                                ssll = sssll;
+                            }
+                            ssll.setHost(host);
+                            ssll.setPort(sslPort);
                             ssll.setMaxIdleTime(90*1000);  // default 10 sec
                             ssll.setName("ConsoleSocket");   // all with same name will use the same thread pool
-                            ssll.setUseDirectBuffers(false);  // default true seems to be leaky
                             //_server.addConnector(ssll);
                             connectors.add(ssll);
                             boundAddresses++;
                         } catch (Exception e) {
                             System.err.println("Unable to bind routerconsole to " + host + " port " + sslPort + " for SSL: " + e);
+                            if (SystemVersion.isGNU())
+                                System.err.println("Probably because GNU classpath does not support Sun keystores");
                             System.err.println("You may ignore this warning if the console is still available at https://localhost:" + sslPort);
                         }
                     }
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 825133c0ee..199cf5e4e3 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java
@@ -67,12 +67,10 @@ public class StatSummarizer implements Runnable {
     
     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
+        if (SystemVersion.isApache() ||            // Harmony
+            SystemVersion.isGNU()) {               // JamVM or gij
             _log.logAlways(Log.WARN, "Graphing not supported with this JVM: " +
-                                     vendor + ' ' +
+                                     System.getProperty("java.vendor") + ' ' +
                                      System.getProperty("java.version") + " (" +
                                      System.getProperty("java.runtime.name") + ' ' +
                                      System.getProperty("java.runtime.version") + ')');
diff --git a/core/java/src/net/i2p/crypto/SHA1.java b/core/java/src/net/i2p/crypto/SHA1.java
index 7ea68de562..bfe07630ca 100644
--- a/core/java/src/net/i2p/crypto/SHA1.java
+++ b/core/java/src/net/i2p/crypto/SHA1.java
@@ -20,6 +20,8 @@ import java.security.DigestException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 
+import net.i2p.util.SystemVersion;
+
 /**
  * NOTE: As of 0.8.7, use getInstance() instead of new SHA1(), which will
  * return the JVM's MessageDigest if it is faster.
@@ -94,10 +96,8 @@ public final class SHA1 extends MessageDigest implements Cloneable {
     static {
         // oddly, Bitzi is faster than Oracle - see test results below
         boolean useBitzi = true;
-        String vendor = System.getProperty("java.vendor");
-        if (vendor.startsWith("Apache") ||                      // Harmony
-            vendor.startsWith("GNU Classpath") ||               // JamVM
-            vendor.startsWith("Free Software Foundation")) {    // gij
+        if (SystemVersion.isApache() ||            // Harmony
+            SystemVersion.isGNU()) {               // JamVM or gij
             try {
                 MessageDigest.getInstance("SHA-1");
                 useBitzi = false;
diff --git a/core/java/src/net/i2p/util/ReusableGZIPInputStream.java b/core/java/src/net/i2p/util/ReusableGZIPInputStream.java
index f09c9711c3..5ef5b7801f 100644
--- a/core/java/src/net/i2p/util/ReusableGZIPInputStream.java
+++ b/core/java/src/net/i2p/util/ReusableGZIPInputStream.java
@@ -9,7 +9,7 @@ import java.util.concurrent.LinkedBlockingQueue;
 public class ReusableGZIPInputStream extends ResettableGZIPInputStream {
     // Apache Harmony 5.0M13 Deflater doesn't work after reset()
     // Neither does Android
-    private static final boolean ENABLE_CACHING = !(System.getProperty("java.vendor").startsWith("Apache") ||
+    private static final boolean ENABLE_CACHING = !(SystemVersion.isApache() ||
                                                     SystemVersion.isAndroid());
     private static final LinkedBlockingQueue<ReusableGZIPInputStream> _available;
     static {
diff --git a/core/java/src/net/i2p/util/ReusableGZIPOutputStream.java b/core/java/src/net/i2p/util/ReusableGZIPOutputStream.java
index fe686095e4..3cbf1dd335 100644
--- a/core/java/src/net/i2p/util/ReusableGZIPOutputStream.java
+++ b/core/java/src/net/i2p/util/ReusableGZIPOutputStream.java
@@ -20,7 +20,7 @@ import net.i2p.data.DataHelper;
 public class ReusableGZIPOutputStream extends ResettableGZIPOutputStream {
     // Apache Harmony 5.0M13 Deflater doesn't work after reset()
     // Neither does Android
-    private static final boolean ENABLE_CACHING = !(System.getProperty("java.vendor").startsWith("Apache") ||
+    private static final boolean ENABLE_CACHING = !(SystemVersion.isApache() ||
                                                     SystemVersion.isAndroid());
     private static final LinkedBlockingQueue<ReusableGZIPOutputStream> _available;
     static {
diff --git a/core/java/src/net/i2p/util/SystemVersion.java b/core/java/src/net/i2p/util/SystemVersion.java
index d43cddc898..484a293238 100644
--- a/core/java/src/net/i2p/util/SystemVersion.java
+++ b/core/java/src/net/i2p/util/SystemVersion.java
@@ -15,14 +15,23 @@ public abstract class SystemVersion {
 
     private static final boolean _isWin = System.getProperty("os.name").startsWith("Win");
     private static final boolean _isMac = System.getProperty("os.name").startsWith("Mac");
-    private static final boolean _isAndroid = System.getProperty("java.vendor").contains("Android");
+    private static final boolean _isAndroid;
+    private static final boolean _isApache;
+    private static final boolean _isGNU;
     private static final boolean _is64 = "64".equals(System.getProperty("sun.arch.data.model")) ||
                                          System.getProperty("os.arch").contains("64");
+    private static final boolean _hasWrapper = System.getProperty("wrapper.version") != null;
 
     private static final boolean _oneDotSix;
     private static final int _androidSDK;
 
     static {
+        String vendor = System.getProperty("java.vendor");
+        _isAndroid = vendor.contains("Android");
+        _isApache = vendor.startsWith("Apache");
+        _isGNU = vendor.startsWith("GNU Classpath") ||               // JamVM
+                 vendor.startsWith("Free Software Foundation");      // gij
+
         int sdk = 0;
         if (_isAndroid) {
             try {
@@ -52,6 +61,20 @@ public abstract class SystemVersion {
         return _isAndroid;
     }
 
+    /**
+     *  Apache Harmony JVM, or Android
+     */
+    public static boolean isApache() {
+        return _isApache || _isAndroid;
+    }
+
+    /**
+     *  gij or JamVM with GNU Classpath
+     */
+    public static boolean isGNU() {
+        return _isGNU;
+    }
+
     /**
      *  Better than (new VersionComparator()).compare(System.getProperty("java.version"), "1.6") >= 0
      *  as it handles Android also, where java.version = "0".
@@ -90,6 +113,6 @@ public abstract class SystemVersion {
      *  Same as I2PAppContext.hasWrapper()
      */
     public static boolean hasWrapper() {
-        return System.getProperty("wrapper.version") != null;
+        return _hasWrapper;
     }
 }
diff --git a/installer/resources/eepsite/jetty.xml b/installer/resources/eepsite/jetty.xml
index ba30a55ebd..0e873ca770 100644
--- a/installer/resources/eepsite/jetty.xml
+++ b/installer/resources/eepsite/jetty.xml
@@ -90,7 +90,9 @@
 
     <!-- Use this connector for many frequently idle connections
          and for threadless continuations.
-         Not recommended on Java 5 - comment out and uncomment the
+         Not recommended on Java 5 - comment this out, and uncomment the
+         SocketConnector below.
+         Do not use for gij or JamVM - comment this out, and uncomment the
          SocketConnector below.
     -->    
     <Call name="addConnector">
-- 
GitLab