package net.sourceforge.eclipsejetty.jetty;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import net.sourceforge.eclipsejetty.JettyPlugin;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
public class JettyVersion
{
private static class CacheKey
{
private final String jettyPath;
private final boolean embedded;
public CacheKey(String jettyPath, boolean embedded)
{
super();
this.jettyPath = jettyPath;
this.embedded = embedded;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = (prime * result) + (embedded ? 1231 : 1237);
result = (prime * result) + ((jettyPath == null) ? 0 : jettyPath.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
CacheKey other = (CacheKey) obj;
if (embedded != other.embedded)
{
return false;
}
if (jettyPath == null)
{
if (other.jettyPath != null)
{
return false;
}
}
else if (!jettyPath.equals(other.jettyPath))
{
return false;
}
return true;
}
}
private static final long MAX_TIME_TO_LIVE = 60 * 1000;
private static final Map<CacheKey, JettyVersion> CACHE = new HashMap<CacheKey, JettyVersion>();
public static JettyVersion detect(String jettyPath, boolean embedded)
{
CacheKey cacheKey = new CacheKey(jettyPath, embedded);
JettyVersion version = CACHE.get(cacheKey);
if ((version != null) && ((System.currentTimeMillis() - version.timestamp) < MAX_TIME_TO_LIVE))
{
return version;
}
if (embedded)
{
try
{
URL url = FileLocator.find(JettyPlugin.getDefault().getBundle(),
Path.fromOSString("lib/jetty/jetty-server.jar"), null);
if (url == null)
{
throw new IllegalArgumentException(
"Could not detect Jetty version of embedded Jetty (did not find jetty-server.jar)");
}
version = new JettyVersion(detect(new File(FileLocator.toFileURL(url).getFile())), true);
}
catch (IOException e)
{
throw new IllegalArgumentException("Could not detect Jetty version of embedded Jetty", e);
}
}
else
{
final File jettyLibDir = new File(jettyPath, "lib");
if (!jettyLibDir.exists() || !jettyLibDir.isDirectory())
{
throw new IllegalArgumentException("Could not find Jetty libs");
}
for (File file : jettyLibDir.listFiles())
{
if (!file.isFile())
{
continue;
}
String name = file.getName();
if ((name.startsWith("jetty-")) && (name.endsWith(".jar")))
{
String value = detect(file);
if (value != null)
{
version = new JettyVersion(value, false);
break;
}
}
}
}
if (version == null)
{
throw new IllegalArgumentException("Failed to detect Jetty version");
}
if (!version.isValid())
{
throw new IllegalArgumentException("Invalid Jetty version detected");
}
CACHE.put(cacheKey, version);
return version;
}
protected static String detect(File file)
{
if ((!file.exists()) || (!file.canRead()))
{
return null;
}
try
{
JarFile jarFile = new JarFile(file);
try
{
Manifest manifest = jarFile.getManifest();
if (manifest == null)
{
return null;
}
Attributes attributes = manifest.getMainAttributes();
if ((attributes == null) || (attributes.size() == 0))
{
return null;
}
return attributes.getValue("Implementation-Version");
}
finally
{
jarFile.close();
}
}
catch (IOException e)
{
// failed to read jar file
return null;
}
}
private final long timestamp;
private final String version;
private final Integer majorVersion;
private final Integer minorVersion;
private final Integer microVersion;
private final JettyVersionType type;
protected JettyVersion(String version, boolean embedded)
{
super();
timestamp = System.currentTimeMillis();
this.version = version;
majorVersion = extractMajorVersion(version);
minorVersion = extractMinorVersion(version);
microVersion = extractMicroVersion(version);
type = extractType(majorVersion, minorVersion, embedded);
}
public String getVersion()
{
return version;
}
public Integer getMajorVersion()
{
return majorVersion;
}
public Integer getMinorVersion()
{
return minorVersion;
}
public Integer getMicroVersion()
{
return microVersion;
}
public JettyVersionType getType()
{
return type;
}
public boolean isValid()
{
return type != null;
}
@Override
public String toString()
{
return String.format("%s (%s, major=%s, minor=%s, micro=%s)", version, type, majorVersion, minorVersion,
microVersion);
}
private static Integer extractMajorVersion(String version)
{
return extractVersion(version, 0);
}
private static Integer extractMinorVersion(String version)
{
return extractVersion(version, 1);
}
private static Integer extractMicroVersion(String version)
{
return extractVersion(version, 2);
}
private static Integer extractVersion(String version, int index)
{
if (version == null)
{
return null;
}
String[] split = version.split("\\.");
if (split.length <= index)
{
return null;
}
try
{
return Integer.parseInt(split[index]);
}
catch (NumberFormatException e)
{
return null;
}
}
private static JettyVersionType extractType(Integer majorVersion, Integer minorVersion, boolean embedded)
{
if (embedded)
{
return JettyVersionType.JETTY_EMBEDDED;
}
if (majorVersion == null)
{
return null;
}
switch (majorVersion.intValue())
{
case 6:
return JettyVersionType.JETTY_6;
case 7:
return JettyVersionType.JETTY_7;
case 8:
return JettyVersionType.JETTY_8;
case 9:
{
if (minorVersion.intValue() <= 2)
{
return JettyVersionType.JETTY_9;
}
else
{
return JettyVersionType.JETTY_9_3;
}
}
default:
return null;
}
}
}