/******************************************************************************* | |
* Copyright (c) 2010 Angelo Zerr and others. | |
* 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: | |
* Angelo Zerr <angelo.zerr@gmail.com> - Initial API and implementation | |
*******************************************************************************/ | |
package org.eclipse.jst.server.jetty.core.internal; | |
import java.io.File; | |
import java.io.IOException; | |
import java.text.MessageFormat; | |
import java.util.Collection; | |
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.concurrent.ConcurrentHashMap; | |
import org.eclipse.core.runtime.IPath; | |
import org.eclipse.core.runtime.IProgressMonitor; | |
import org.eclipse.core.runtime.IStatus; | |
import org.eclipse.core.runtime.Path; | |
import org.eclipse.core.runtime.Status; | |
import org.eclipse.debug.core.ILaunch; | |
import org.eclipse.debug.core.ILaunchManager; | |
import org.eclipse.debug.core.Launch; | |
import org.eclipse.debug.core.model.IStreamsProxy; | |
import org.eclipse.jdt.launching.IRuntimeClasspathEntry; | |
import org.eclipse.jdt.launching.IVMInstall; | |
import org.eclipse.jdt.launching.IVMInstallType; | |
import org.eclipse.jdt.launching.IVMRunner; | |
import org.eclipse.jdt.launching.JavaRuntime; | |
import org.eclipse.jdt.launching.VMRunnerConfiguration; | |
import org.eclipse.jst.server.jetty.core.IJettyRuntimeWorkingCopy; | |
import org.eclipse.jst.server.jetty.core.JettyPlugin; | |
import org.eclipse.jst.server.jetty.core.internal.util.StringUtils; | |
import org.eclipse.wst.server.core.IRuntimeType; | |
import org.eclipse.wst.server.core.model.RuntimeDelegate; | |
/** | |
* Jetty Runtime. | |
* | |
*/ | |
public class JettyRuntime extends RuntimeDelegate implements IJettyRuntime, | |
IJettyRuntimeWorkingCopy { | |
//private static final String TOOLS_JAR_PATH = "lib" + File.separator + "tools.jar"; | |
private static final String JAVAC_MAIN = "com.sun.tools.javac.Main"; | |
private static final String CLASS_DETECTOR = "org.eclipse.jst.server.Jetty.core.internal.ClassDetector"; | |
protected static final String PROP_VM_INSTALL_TYPE_ID = "vm-install-type-id"; | |
protected static final String PROP_VM_INSTALL_ID = "vm-install-id"; | |
protected static Map<File, Boolean> sdkMap = new HashMap<File, Boolean>(2); | |
private static Map<String, Integer> javaVersionMap = new ConcurrentHashMap<String, Integer>(); | |
public JettyRuntime() { | |
// do nothing | |
} | |
public IJettyVersionHandler getVersionHandler() { | |
IRuntimeType type = getRuntime().getRuntimeType(); | |
return JettyPlugin.getJettyVersionHandler(type.getId()); | |
} | |
protected String getVMInstallTypeId() { | |
return getAttribute(PROP_VM_INSTALL_TYPE_ID, (String) null); | |
} | |
protected String getVMInstallId() { | |
return getAttribute(PROP_VM_INSTALL_ID, (String) null); | |
} | |
public boolean isUsingDefaultJRE() { | |
return getVMInstallTypeId() == null; | |
} | |
public IVMInstall getVMInstall() { | |
if (getVMInstallTypeId() == null) | |
return JavaRuntime.getDefaultVMInstall(); | |
try { | |
IVMInstallType vmInstallType = JavaRuntime | |
.getVMInstallType(getVMInstallTypeId()); | |
IVMInstall[] vmInstalls = vmInstallType.getVMInstalls(); | |
int size = vmInstalls.length; | |
String id = getVMInstallId(); | |
for (int i = 0; i < size; i++) { | |
if (id.equals(vmInstalls[i].getId())) | |
return vmInstalls[i]; | |
} | |
} catch (Exception e) { | |
// ignore | |
} | |
return null; | |
} | |
public Collection<IRuntimeClasspathEntry> getRuntimeClasspath( | |
IPath configPath) { | |
IPath installPath = getRuntime().getLocation(); | |
// If installPath is relative, convert to canonical path and hope for | |
// the best | |
if (!installPath.isAbsolute()) { | |
try { | |
String installLoc = (new File(installPath.toOSString())) | |
.getCanonicalPath(); | |
installPath = new Path(installLoc); | |
} catch (IOException e) { | |
// Ignore if there is a problem | |
} | |
} | |
return getVersionHandler().getRuntimeClasspath(installPath, configPath); | |
} | |
/** | |
* Verifies the Jetty installation directory. If it is correct, true is | |
* returned. Otherwise, the user is notified and false is returned. | |
* | |
* @return boolean | |
*/ | |
public IStatus verifyLocation() { | |
return getVersionHandler() | |
.verifyInstallPath(getRuntime().getLocation()); | |
} | |
/* | |
* Validate the runtime | |
*/ | |
public IStatus validate() { | |
IStatus status = super.validate(); | |
if (!status.isOK()) | |
return status; | |
status = verifyLocation(); | |
if (!status.isOK()) | |
return status; | |
// don't accept trailing space since that can cause startup problems | |
if (getRuntime().getLocation().hasTrailingSeparator()) | |
return new Status(IStatus.ERROR, JettyPlugin.PLUGIN_ID, 0, | |
Messages.errorInstallDirTrailingSlash, null); | |
if (getVMInstall() == null) | |
return new Status(IStatus.ERROR, JettyPlugin.PLUGIN_ID, 0, | |
Messages.errorJRE, null); | |
// check for tools.jar (contains the javac compiler on Windows & Linux) | |
// to see whether | |
// Jetty will be able to compile JSPs. | |
// boolean found = false; | |
// File file = getVMInstall().getInstallLocation(); | |
// if (file != null) { | |
// File toolsJar = new File(file, TOOLS_JAR_PATH); | |
// if (toolsJar.exists()) | |
// found = true; | |
// } | |
status = getVersionHandler().validate(getRuntime().getLocation(), getVMInstall()); | |
if (status != null) { | |
return status; | |
} | |
return Status.OK_STATUS; | |
// // on Jetty 5.5 and 6.0, the Eclipse JDT compiler is used for JSP's | |
// String id = getRuntime().getRuntimeType().getId(); | |
// if (!found) { | |
// if (id != null && (id.indexOf("55") > 0 || id.indexOf("60") > 0)) | |
// found = true; | |
// } | |
// | |
// // on Mac, tools.jar is merged into classes.zip. if tools.jar wasn't | |
// // found, | |
// // try loading the javac class by running a check inside the VM | |
// if (!found) { | |
// String os = Platform.getOS(); | |
// if (os != null && os.toLowerCase().indexOf("mac") >= 0) | |
// found = checkForCompiler(); | |
// } | |
// | |
// if (!found) | |
// return new Status(IStatus.WARNING, JettyPlugin.PLUGIN_ID, 0, | |
// Messages.warningJRE, null); | |
// | |
// File f = getRuntime().getLocation().append("conf").toFile(); | |
// File[] conf = f.listFiles(); | |
// if (conf != null) { | |
// int size = conf.length; | |
// for (int i = 0; i < size; i++) { | |
// if (!f.canRead()) | |
// return new Status(IStatus.WARNING, JettyPlugin.PLUGIN_ID, | |
// 0, Messages.warningCantReadConfig, null); | |
// } | |
// } | |
// | |
// // For Jetty 6.0, ensure we have J2SE 5.0 | |
// if (id != null && id.indexOf("60") > 0) { | |
// IVMInstall vmInstall = getVMInstall(); | |
// if (vmInstall instanceof IVMInstall2) { | |
// String javaVersion = ((IVMInstall2) vmInstall).getJavaVersion(); | |
// if (javaVersion != null | |
// && !isVMMinimumVersion(javaVersion, 105)) { | |
// return new Status(IStatus.ERROR, JettyPlugin.PLUGIN_ID, 0, | |
// Messages.errorJREJetty60, null); | |
// } | |
// } | |
// } | |
// // Else for Jetty 7.0, ensure we have J2SE 6.0 | |
// else if (id != null && id.indexOf("70") > 0) { | |
// IVMInstall vmInstall = getVMInstall(); | |
// if (vmInstall instanceof IVMInstall2) { | |
// String javaVersion = ((IVMInstall2) vmInstall).getJavaVersion(); | |
// if (javaVersion != null | |
// && !isVMMinimumVersion(javaVersion, 106)) { | |
// return new Status(IStatus.ERROR, JettyPlugin.PLUGIN_ID, 0, | |
// Messages.errorJREJetty70, null); | |
// } | |
// } | |
// } | |
// return Status.OK_STATUS; | |
} | |
/** | |
* @see RuntimeDelegate#setDefaults(IProgressMonitor) | |
*/ | |
public void setDefaults(IProgressMonitor monitor) { | |
IRuntimeType type = getRuntimeWorkingCopy().getRuntimeType(); | |
getRuntimeWorkingCopy().setLocation( | |
new Path(JettyPlugin.getPreference("location" + type.getId()))); | |
} | |
public void setVMInstall(IVMInstall vmInstall) { | |
if (vmInstall == null) { | |
setVMInstall(null, null); | |
} else | |
setVMInstall(vmInstall.getVMInstallType().getId(), | |
vmInstall.getId()); | |
} | |
protected void setVMInstall(String typeId, String id) { | |
if (typeId == null) | |
setAttribute(PROP_VM_INSTALL_TYPE_ID, (String) null); | |
else | |
setAttribute(PROP_VM_INSTALL_TYPE_ID, typeId); | |
if (id == null) | |
setAttribute(PROP_VM_INSTALL_ID, (String) null); | |
else | |
setAttribute(PROP_VM_INSTALL_ID, id); | |
} | |
/** | |
* Checks for the existence of the Java compiler in the given java | |
* executable. A main program is run (<code>org.eclipse.jst.Jetty.core. | |
* internal.ClassDetector</code>), that dumps a true or false value | |
* depending on whether the compiler is found. This output is then parsed | |
* and cached for future reference. | |
* | |
* @return true if the compiler was found | |
*/ | |
protected boolean checkForCompiler() { | |
// first try the cache | |
File javaHome = getVMInstall().getInstallLocation(); | |
try { | |
Boolean b = (Boolean) sdkMap.get(javaHome); | |
return b.booleanValue(); | |
} catch (Exception e) { | |
// ignore | |
} | |
// locate Jettycore.jar - it contains the class detector main program | |
File file = JettyPlugin.getPlugin(); | |
if (file != null && file.exists()) { | |
IVMRunner vmRunner = getVMInstall().getVMRunner( | |
ILaunchManager.RUN_MODE); | |
VMRunnerConfiguration config = new VMRunnerConfiguration( | |
CLASS_DETECTOR, | |
new String[] { file.getAbsolutePath() }); | |
config.setProgramArguments(new String[] { JAVAC_MAIN }); | |
ILaunch launch = new Launch(null, ILaunchManager.RUN_MODE, null); | |
try { | |
vmRunner.run(config, launch, null); | |
for (int i = 0; i < 600; i++) { | |
// wait no more than 30 seconds (600 * 50 mils) | |
if (launch.isTerminated()) { | |
break; | |
} | |
try { | |
Thread.sleep(50); | |
} catch (InterruptedException e) { | |
// ignore | |
} | |
} | |
IStreamsProxy streamsProxy = launch.getProcesses()[0] | |
.getStreamsProxy(); | |
String text = null; | |
if (streamsProxy != null) { | |
text = streamsProxy.getOutputStreamMonitor().getContents(); | |
if (text != null && text.length() > 0) { | |
boolean found = false; | |
if (StringUtils.isTrue(text)) | |
found = true; | |
sdkMap.put(javaHome, new Boolean(found)); | |
return found; | |
} | |
} | |
} catch (Exception e) { | |
Trace.trace(Trace.SEVERE, "Error checking for JDK", e); | |
} finally { | |
if (!launch.isTerminated()) { | |
try { | |
launch.terminate(); | |
} catch (Exception ex) { | |
// ignore | |
} | |
} | |
} | |
} | |
// log error that we were unable to check for the compiler | |
JettyPlugin.log(MessageFormat.format("Failed compiler check for {0}", | |
javaHome.getAbsolutePath())); | |
return false; | |
} | |
private boolean isVMMinimumVersion(String javaVersion, int minimumVersion) { | |
Integer version = (Integer) javaVersionMap.get(javaVersion); | |
if (version == null) { | |
int index = javaVersion.indexOf('.'); | |
if (index > 0) { | |
try { | |
int major = Integer.parseInt(javaVersion | |
.substring(0, index)) * 100; | |
index++; | |
int index2 = javaVersion.indexOf('.', index); | |
if (index2 > 0) { | |
int minor = Integer.parseInt(javaVersion.substring( | |
index, index2)); | |
version = new Integer(major + minor); | |
javaVersionMap.put(javaVersion, version); | |
} | |
} catch (NumberFormatException e) { | |
// Ignore | |
} | |
} | |
} | |
// If we have a version, and it's less than the minimum, fail the check | |
if (version != null && version.intValue() < minimumVersion) { | |
return false; | |
} | |
return true; | |
} | |
} |