package de.uni_hannover.sra.minimax_simulator; import de.uni_hannover.sra.minimax_simulator.io.IOUtils; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Provides methods for reading version information from JAR's manifest, Java version of the running JVM * and to check Java versions against each other. * * @author Martin Lück */ public class Version { /** whether or not the application runs from a JAR file */ private boolean isJar = false; /** name of the application */ private String moduleName = ""; /** revision number of the application */ private String revisionNumber = ""; /** version number of the application */ private String versionNumber = ""; /** Java version used for packaging */ private String buildJdk = ""; /** date and time of application packaging */ private String buildTime = ""; /** name of the application's author */ private String authorName = ""; /** name of the application's company */ private String companyName = ""; /** major version of the running JVM */ private int jvmMajor; /** feature version of the running JVM */ private int jvmFeature; /** update version of the running JVM */ private int jvmUpdate; /** build version of the running JVM */ private int jvmBuild; /** logger */ private static final Logger LOG = Logger.getLogger("de.uni_hannover.sra.minimax_simulator"); /** * Constructs a new {@code Version} instance.<br> * Tries to read version information from JAR's manifest and reads the Java version of the running JVM. * * @param c * the class to use for getting the JAR file */ public Version(Class<?> c) { setJavaVersion(); if (c == null) { return; } File jarName = null; try { jarName = getResourceJar(c); if (jarName == null) { return; } JarFile jarFile = null; try { jarFile = new JarFile(jarName); Attributes attrs = jarFile.getManifest().getMainAttributes(); setBuildTime(attrs); setBuildJdk(attrs); setRevisionNumber(attrs); setVersionNumber(attrs); setModuleName(attrs); setAuthor(attrs); setCompany(attrs); setIsJar(true); } finally { IOUtils.closeQuietly(jarFile); } } catch (IOException e) { // no jar file LOG.log(Level.CONFIG, "application not running from JAR", e); } } /** * Convert the specified class name to URL to get the file path of the JAR that contains the class. * * @param c * the class to get the JAR containing the class * @return * the JAR containing the class or {@code null} if the class is not contained in a JAR */ private static File getResourceJar(Class<?> c) { String resource = c.getName().replace('.', '/') + ".class"; URL url = ClassLoader.getSystemResource(resource); if (url != null) { String u = url.toString(); if (u.startsWith("jar:file:")) { int idx = u.indexOf("!"); String jarName = u.substring(4, idx); try { return new File(new URI(jarName)); } catch (URISyntaxException e) { LOG.log(Level.CONFIG, "could not find JAR file containing the class: " + c.getSimpleName(), e); return null; } } } return null; } /** * Reads the application version number from the manifest. * * @param attrs * the {@code Attributes} from the manifest */ private void setVersionNumber(Attributes attrs) { String versionNumber = attrs.getValue("Implementation-Version"); if (versionNumber != null) { this.versionNumber = versionNumber; } } /** * Reads the application build number from the manifest. * * @param attrs * the {@code Attributes} from the manifest */ private void setRevisionNumber(Attributes attrs) { String revisionNumber = attrs.getValue("Implementation-Build"); if (revisionNumber != null) { this.revisionNumber = revisionNumber; } } /** * Reads the build JDK version from the manifest. * * @param attrs * the {@code Attributes} from the manifest */ private void setBuildJdk(Attributes attrs) { String buildJdk = attrs.getValue("Build-Jdk"); if (buildJdk != null) { this.buildJdk = buildJdk; } } /** * Reads the build time from the manifest. * * @param attrs * the {@code Attributes} from the manifest */ private void setBuildTime(Attributes attrs) { String buildTime = attrs.getValue("Build-Time"); if (buildTime != null) { this.buildTime = buildTime; } } /** * Reads the application's name from the manifest. * * @param attrs * the {@code Attributes} from the manifest */ private void setModuleName(Attributes attrs) { String moduleName = attrs.getValue("Implementation-Name"); if (moduleName != null) { this.moduleName = moduleName; } } /** * Reads the application's authors from the manifest. * * @param attrs * the {@code Attributes} from the manifest */ private void setAuthor(Attributes attrs) { String authorName = attrs.getValue("Additional-Author"); if (authorName != null) { this.authorName = authorName; } } /** * Reads the application's company from the manifest. * * @param attrs * the {@code Attributes} from the manifest */ private void setCompany(Attributes attrs) { String companyName = attrs.getValue("Additional-Company"); if (companyName != null) { this.companyName = companyName; } } /** * Reads the Java version of the currently running JVM. */ private void setJavaVersion() { String jv = System.getProperty("java.version"); try { String[] p0 = jv.split("_"); String[] p1 = p0[0].split("\\."); jvmMajor = Integer.parseInt(p1[0]); jvmFeature = Integer.parseInt(p1[1]); jvmUpdate = Integer.parseInt(p1[2]); try { jvmBuild = Integer.parseInt(p0[1]); } catch (Exception e) { LOG.log(Level.CONFIG, "could not parse JVM build", e); Pattern numberPattern = Pattern.compile("[0-9]+"); Matcher m = numberPattern.matcher(p0[1]); if (m.find()) { jvmBuild = Integer.parseInt(m.group(0)); } } } catch (Exception e) { // ignore LOG.log(Level.CONFIG, "could not parse Java version", e); } } /** * Sets the value of the {@code is JAR} property. * * @param isLoaded * whether the class was loaded from JAR or not. */ private void setIsJar(boolean isLoaded) { isJar = isLoaded; } /** * Gets the application's build number. * * @return * the application's build number */ public String getRevisionNumber() { return revisionNumber; } /** * Gets the application's version number. * * @return * the application's version number */ public String getVersionNumber() { return versionNumber; } /** * Gets the JDK version the application was built with. * * @return * the build JDK version */ public String getBuildJdk() { return buildJdk; } /** * Gets the application's build time. * * @return * the application's build time */ public String getBuildTime() { return buildTime; } /** * Gets the application's name. * * @return * the name of the application */ public String getModuleName() { return moduleName; } /** * Gets the name(s) of the application's author(s). * * @return * the name(s) of the application's author(s). */ public String getAuthorName() { return authorName; } /** * Gets the name of the application's company. * * @return * the name of the company of the application */ public String getCompanyName() { return companyName; } /** * Gets the value of the {@code is JAR} property. * * @return * {@code true} if the application was loaded from JAR, {@code false} otherwise */ public boolean isJar() { return isJar; } /** * Gets the full information of the application's version.<br> * <br> * This includes the application's name, version number, build number, build time and build JDK. * * @return * an array containing the full information of the version */ public String[] getFullInfoStrings() { return new String[] { "[Module: " + getModuleName() + "]", "Version: " + getVersionNumber() + " - " + "Revision: " + getRevisionNumber() + " - " + "Time: " + getBuildTime() + " - " + "Build JDK: " + getBuildJdk() }; } /** * Gets the short information of the application's version.<br> * <br> * This includes the application's name, version number and build number. * * @return * an array containing the short information of the version */ public String[] getShortInfoStrings() { return new String[] { "[Module: " + getModuleName() + "]", "Version: " + getVersionNumber() + " - " + "Revision: " + getRevisionNumber() }; } /** * Gets the major version number of the currently running JVM. * * @return * the JVM's major version number */ public int getJvmMajor() { return jvmMajor; } /** * Gets the feature version number of the currently running JVM. * * @return * the JVM's feature version number */ public int getJvmFeature() { return jvmFeature; } /** * Gets the update version number of the currently running JVM. * * @return * the JVM's update version number */ public int getJvmUpdate() { return jvmUpdate; } /** * Gets the build version number of the currently running JVM. * * @return * the JVM's build version number */ public int getJvmBuild() { return jvmBuild; } /** * Compares the Java version of the currently running JVM with the specified Java version. * * @param major * the major version number * @param feature * the feature version number * @param update * the update version number * @param build * the build version number * @return * {@code -1} if the version of the running JVM is lower than the specified one,<br> * {@code 1} if it is higher and<br> * {@code 0} if they are equal */ private int compareTo(int major, int feature, int update, int build) { final int[] jvm = {jvmMajor, jvmFeature, jvmUpdate, jvmBuild}; final int[] compareTo = {major, feature, update, build}; for (int i = 0; i < jvm.length; i++) { if (jvm[i] < compareTo[i]) { return -1; } else if (jvm[i] > compareTo[i]) { return 1; } } return 0; } /** * Checks if the Java version of the currently running JVM is equal to the specified Java version. * * @param major * the major version number * @param feature * the feature version number * @param update * the update version number * @param build * the build version number * @return * {@code true} if the version numbers are equal, {@code false} otherwise */ public boolean isJvmEqual(int major, int feature, int update, int build) { return compareTo(major, feature, update, build) == 0; } /** * Checks if the Java version of the currently running JVM is lower than the specified version number. * * @param major * the major version number * @param feature * the feature version number * @param update * the update version number * @param build * the build version number * @return * {@code true} if the current Java version is lower, {@code false} otherwise */ public boolean isJvmLower(int major, int feature, int update, int build) { return compareTo(major, feature, update, build) == -1; } /** * Checks if the Java version of the currently running JVM is lower or equal to the specified version number. * * @param major * the major version number * @param feature * the feature version number * @param update * the update version number * @param build * the build version number * @return * {@code true} if the current Java version of lower or equal, {@code false} otherwise */ public boolean isJvmLowerOrEqual(int major, int feature, int update, int build) { int compare = compareTo(major, feature, update, build); return compare == 0 || compare == -1; } /** * Checks if the Java version of the currently running JVM is higher than the specified version number. * * @param major * the major version number * @param feature * the feature version number * @param update * the update version number * @param build * the build version number * @return * {@code true} if the current Java version is higher, {@code false} otherwise */ public boolean isJvmHigher(int major, int feature, int update, int build) { return compareTo(major, feature, update, build) == 1; } /** * Checks if the Java version of the currently running JVM is higher or equal to the specified version number. * * @param major * the major version number * @param feature * the feature version number * @param update * the update version number * @param build * the build version number * @return * {@code true} if the current Java version is higher or equal, {@code false} otherwise */ public boolean isJvmHigherOrEqual(int major, int feature, int update, int build) { int compare = compareTo(major, feature, update, build); return compare == 0 || compare == 1; } }