Bug 82068 - Eclipse crashes without proper error to the user when the java version is not new enough
diff --git a/platform/org.eclipse.platform/src/org/eclipse/core/launcher/Main.java b/platform/org.eclipse.platform/src/org/eclipse/core/launcher/Main.java
index 34d4f27..710efd1 100644
--- a/platform/org.eclipse.platform/src/org/eclipse/core/launcher/Main.java
+++ b/platform/org.eclipse.platform/src/org/eclipse/core/launcher/Main.java
@@ -101,6 +101,8 @@
 	private static final String ECLIPSE_PROPERTIES = "eclipse.properties"; //$NON-NLS-1$
 	private static final String FILE_SCHEME = "file:"; //$NON-NLS-1$	
 
+	private static final String DEFAULT_JRE_REQUIRED = "1.4.1"; //$NON-NLS-1$
+	
 	// constants: configuration file location
 	private static final String CONFIG_DIR = "configuration/"; //$NON-NLS-1$
 	private static final String CONFIG_FILE = "config.ini"; //$NON-NLS-1$
@@ -126,6 +128,7 @@
 	private static final String PROP_CLASSPATH = "osgi.frameworkClassPath"; //$NON-NLS-1$
 	private static final String PROP_EXTENSIONS = "osgi.framework.extensions"; //$NON-NLS-1$
 	private static final String PROP_LOGFILE = "osgi.logfile"; //$NON-NLS-1$
+	private static final String PROP_REQUIRED_JAVA_VERSION = "osgi.requiredJavaVersion"; //$NON-NLS-1$
 	private static final String PROP_EOF = "eof"; //$NON-NLS-1$
 
 	private static final String PROP_EXITCODE = "eclipse.exitcode"; //$NON-NLS-1$
@@ -151,6 +154,68 @@
 	protected File logFile = null;
 	protected BufferedWriter log = null;
 	protected boolean newSession = true;
+	
+	/**
+	 * A structured form for a version identifier.
+	 * 
+	 * @see http://java.sun.com/j2se/versioning_naming.html for information on valid version strings
+	 */
+	static class Identifier {
+		private static final String DELIM = ". _-"; //$NON-NLS-1$
+		private int major, minor, service;
+		Identifier(int major, int minor, int service) {
+			super();
+			this.major = major;
+			this.minor = minor;
+			this.service = service;
+		}
+		/**
+		 * @throws NumberFormatException if cannot parse the major and minor version components
+		 */
+		Identifier(String versionString) {
+			super();
+			StringTokenizer tokenizer = new StringTokenizer(versionString, DELIM);
+
+			// major
+			if (tokenizer.hasMoreTokens())
+				major = Integer.parseInt(tokenizer.nextToken());
+
+			// minor
+			if (tokenizer.hasMoreTokens())
+				minor = Integer.parseInt(tokenizer.nextToken());
+
+			try {
+				// service
+				if (tokenizer.hasMoreTokens())
+					service = Integer.parseInt(tokenizer.nextToken());
+			} catch (NumberFormatException nfe) {
+				// ignore the service qualifier in that case and default to 0
+				// this will allow us to tolerate other non-conventional version numbers 
+			}
+		}
+		/**
+		 * Returns true if this id is considered to be greater than or equal to the given baseline.
+		 * e.g. 
+		 * 1.2.9 >= 1.3.1 -> false
+		 * 1.3.0 >= 1.3.1 -> false
+		 * 1.3.1 >= 1.3.1 -> true
+		 * 1.3.2 >= 1.3.1 -> true
+		 * 2.0.0 >= 1.3.1 -> true
+		 */
+		boolean isGreaterEqualTo(Identifier minimum) {
+			if (major < minimum.major)
+				return false;
+			if (major > minimum.major)
+				return true;
+			// major numbers are equivalent so check minor
+			if (minor < minimum.minor)
+				return false;
+			if (minor > minimum.minor)
+				return true;
+			// minor numbers are equivalent so check service
+			return service >= minimum.service;
+		}
+	}	
 
 	/**
 	 * Executes the launch.
@@ -159,12 +224,17 @@
 	 * @param args command-line arguments
 	 * @exception Exception thrown if a problem occurs during the launch
 	 */
-	protected Object basicRun(String[] args) throws Exception {
+	protected void basicRun(String[] args) throws Exception {
 		System.getProperties().setProperty("eclipse.startTime", Long.toString(System.currentTimeMillis())); //$NON-NLS-1$
 		commands = args;
 		String[] passThruArgs = processCommandLine(args);
 		setupVMProperties();
 		processConfiguration();
+		
+		//ensure minimum Java version
+		if (!checkVersion(System.getProperty("java.version"), System.getProperty(PROP_REQUIRED_JAVA_VERSION, DEFAULT_JRE_REQUIRED))) //$NON-NLS-1$
+			return;
+		
 		// need to ensure that getInstallLocation is called at least once to initialize the value.
 		// Do this AFTER processing the configuration to allow the configuration to set
 		// the install location.  
@@ -182,7 +252,7 @@
 		Class clazz = loader.loadClass(STARTER);
 		Method method = clazz.getDeclaredMethod("run", new Class[] {String[].class, Runnable.class}); //$NON-NLS-1$
 		try {
-			return method.invoke(clazz, new Object[] {passThruArgs, endSplashHandler});
+			method.invoke(clazz, new Object[] {passThruArgs, endSplashHandler});
 		} catch (InvocationTargetException e) {
 			if (e.getTargetException() instanceof Error)
 				throw (Error) e.getTargetException();
@@ -195,6 +265,37 @@
 	}
 
 	/**
+	 * Checks whether the given available version is greater or equal to the 
+	 * given required version.
+	 * <p>Will set PROP_EXITCODE/PROP_EXITDATA accordingly if check fails.</p>
+	 *   
+	 * @return a boolean indicating whether the checking passed 
+	 */
+	private boolean checkVersion(String availableVersion, String requiredVersion) {
+		if (requiredVersion == null || availableVersion == null)
+			return true;
+		try {
+			Identifier required = new Identifier(requiredVersion);
+			Identifier available = new Identifier(availableVersion);
+			boolean compatible = available.isGreaterEqualTo(required);
+			if (!compatible) {
+				// any non-zero value should do it - 14 used to be used for version incompatibility in Eclipse 2.1 
+				System.getProperties().put(PROP_EXITCODE, "14"); //$NON-NLS-1$
+				System.getProperties().put(PROP_EXITDATA, "Required Java version: "+ requiredVersion + ". Available: " + availableVersion + '.'); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+			return compatible;
+		} catch (SecurityException e) {
+			// If the security manager won't allow us to get the system property, continue for
+			// now and let things fail later on their own if necessary.
+			return true;
+		} catch (NumberFormatException e) {
+			// If the version string was in a format that we don't understand, continue and
+			// let things fail later on their own if necessary.
+			return true;
+		}
+	}
+	
+	/**
 	 * Returns a string representation of the given URL String.  This converts
 	 * escaped sequences (%..) in the URL into the appropriate characters.
 	 * NOTE: due to class visibility there is a copy of this method
@@ -715,8 +816,6 @@
 				result = 17;
 			}
 		} catch (Throwable e) {
-			// try and take down the splash screen.
-			takeDownSplash();
 			// only log the exceptions if they have not been caught by the 
 			// EclipseStarter (i.e., if the exitCode is not 13) 
 			if (!"13".equals(System.getProperty(PROP_EXITCODE))) { //$NON-NLS-1$
@@ -733,6 +832,9 @@
 			// this constant and display a message to the user telling them that
 			// there is information in their log file.
 			result = 13;
+		} finally {
+			// always try putting down the splash screen just in case the application failed to do so
+			takeDownSplash();			
 		}
 		// Return an int exit code and ensure the system property is set.
 		System.getProperties().put(PROP_EXITCODE, Integer.toString(result));