/******************************************************************************* * Copyright (c) 2012 Pivotal Software, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Pivotal Software, Inc. - initial API and implementation *******************************************************************************/ package org.grails.ide.eclipse.commands; import java.io.File; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.JavaRuntime; import org.grails.ide.eclipse.core.GrailsCoreActivator; /** * Performs a "JDK versus JRE" check that is executed before Grails command executions. If problem is detected * (JRE is used) it shows a message warning the user before executing the command. * * Addresses STS-796: "Grails run command and dependency calculation requires JDK" * * @since 2.6 * @author Kris De Volder */ public class JDKCheck { private static final String CHECK_DISABLED_PREFERENCE = JDKCheck.class.getName()+".disable"; private static final boolean CHECK_DISABLED_DEFAULT = false; private static IEclipsePreferences prefs() { return InstanceScope.INSTANCE.getNode(GrailsCoreActivator.PLUGIN_ID); } /** * The implementation that opens up the dialog belongs in the UI plugin, so we make this * an interface here. */ public static interface IJDKCheckMessageDialog { /** * Open a dialog with a message warning that only JRE is being used. * @param project The project assocuated with executed command, may be null for commands * not associated with a project. * @return */ boolean openMessage(IProject project); } /** * Grails UI plugin provides the real implementation of this! * <p> * This dummy implementation, is here instead of a null pointer and gets used only in case we forget * to initialise this, or get message before UI is initialised. */ public static IJDKCheckMessageDialog ui = new IJDKCheckMessageDialog() { public boolean openMessage(IProject project) { return true; } }; public static void setDisabled(boolean isDisabled) { prefs().putBoolean(CHECK_DISABLED_PREFERENCE, isDisabled); } public static boolean isDisabled() { return prefs().getBoolean(CHECK_DISABLED_PREFERENCE, CHECK_DISABLED_DEFAULT); } public static boolean isEnabled() { boolean result = !isDisabled(); return result; } /** * If dialog is enabled, checks project and shows dialog if problem with JRE is detected. * @return true if command should proceed (no problem, or user chooses to proceed despite warning). */ public static boolean check(final IProject project) { try { if (isEnabled() && hasTheJREProblem(project)) { return ui.openMessage(project); } } catch (ThreadDeath e) { throw e; } catch (Throwable e) { setDisabled(true); // disable this code if it is throwing unexpected exceptions. GrailsCoreActivator.log(e); } return true; } /** * Check if the JVM associated with given project is a JRE (which is a problem). * <p> * This method is conservative and returns 'false' (meaning 'no problem') if there is some problem/uncertainty * determining whether the JVM is a JRE. This is to avoid spurious popups if there is some problem * other than the very specific case we are trying to check for. * * @param project Project associated with command that is being executed, or null (for commands not * associated with a project, such as "create-app", in this case we check the default VM install. */ private static boolean hasTheJREProblem(IProject project) { String os = System.getProperty("os.name"); try { if (os!=null) { if (os.startsWith("Windows") || os.equals("Linux")) { //Note: See http://lopica.sourceforge.net/os.html (list of OS names) //Only consider OS's where we are relatively confident that the check is valid IVMInstall jvm = getVM(project); if (jvm!=null) { File javaHome = jvm.getInstallLocation(); if (javaHome!=null && javaHome.exists()) { File toolsJar = new File(new File(javaHome, "lib"), "tools.jar"); return !toolsJar.exists(); } } } } } catch (CoreException e) { GrailsCoreActivator.log(e); } return false; // Conservatively assume check for 'not a JRE' is passing if unknown OS, or Mac OS, or something went wrong, // or Java home doesn't exist etc. } private static IVMInstall getVM(IProject project) throws CoreException { if (project==null) { return JavaRuntime.getDefaultVMInstall(); } else { return JavaRuntime.getVMInstall(JavaCore.create(project)); } } }