< prev index next >

jdk/src/java.base/share/classes/java/lang/Runtime.java

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 24,36 **** --- 24,48 ---- */ package java.lang; import java.io.*; + import java.math.BigInteger; + import java.util.AbstractList; + import java.util.Arrays; + import java.util.ArrayList; + import java.util.regex.Matcher; + import java.util.regex.Pattern; + import java.util.stream.Collectors; + import java.util.Collections; + import java.util.List; + import java.util.Optional; + import java.util.RandomAccess; import java.util.StringTokenizer; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; + import sun.security.action.GetPropertyAction; /** * Every Java application has a single instance of class * {@code Runtime} that allows the application to interface with * the environment in which the application is running. The current
*** 44,53 **** --- 56,67 ---- */ public class Runtime { private static final Runtime currentRuntime = new Runtime(); + private static Version version; + /** * Returns the runtime object associated with the current Java application. * Most of the methods of class {@code Runtime} are instance * methods and must be invoked with respect to the current runtime object. *
*** 915,920 **** --- 929,1521 ---- @Deprecated(since="1.1", forRemoval=true) public OutputStream getLocalizedOutputStream(OutputStream out) { return out; } + /** + * Returns the version of the Java Runtime Environment as a {@link + * Runtime.Version}. + * + * @return the {@link Runtime.Version} of the Java Runtime Environment + * + * @since 9 + */ + public static Version version() { + if (version == null) { + version = Version.parse( + GetPropertyAction.privilegedGetProperty("java.runtime.version")); + } + return version; + } + + /** + * A representation of a version string for an implemenation of the + * Java&nbsp;SE Platform. A version string contains a version number + * optionally followed by pre-release and build information. + * + * <h2><a name="verNum">Version numbers</a></h2> + * + * <p> A <em>version number</em>, {@code $VNUM}, is a non-empty sequence + * of elements separated by period characters (U+002E). An element is + * either zero, or a unsigned integer numeral without leading zeros. The + * final element in a version number must not be zero. The format is: + * </p> + * + * <blockquote><pre> + * ^[1-9][0-9]*(((\.0)*\.[1-9][0-9]*)*)*$ + * </pre></blockquote> + * + * <p> The sequence may be of arbitrary length but the first three + * elements are assigned specific meanings, as follows:</p> + * + * <blockquote><pre> + * $MAJOR.$MINOR.$SECURITY + * </pre></blockquote> + * + * <ul> + * + * <li><p> <a name="major">{@code $MAJOR}</a> --- The major version + * number, incremented for a major release that contains significant new + * features as specified in a new edition of the Java SE Platform + * Specification, <em>e.g.</em>, <a + * href="https://jcp.org/en/jsr/detail?id=337">JSR 337</a> for + * Java SE 8. Features may be removed in a major release, given + * advance notice at least one major release ahead of time, and + * incompatible changes may be made when justified. The {@code $MAJOR} + * version number of JDK 8 is {@code 8}; the {@code $MAJOR} version + * number of JDK 9 is {@code 9}. When {@code $MAJOR} is incremented, + * all subsequent elements are removed. </p></li> + * + * <li><p> <a name="minor">{@code $MINOR}</a> --- The minor version + * number, incremented for a minor update release that may contain + * compatible bug fixes, revisions to standard APIs mandated by a <a + * href="https://jcp.org/en/procedures/jcp2#5.3">Maintenance Release</a> + * of the relevant Platform Specification, and implementation features + * outside the scope of that Specification such as new JDK-specific APIs, + * additional service providers, new garbage collectors, and ports to new + * hardware architectures. </p></li> + * + * <li><p> <a name="security">{@code $SECURITY}</a> --- The security + * level, incremented for a security update release that contains critical + * fixes including those necessary to improve security. {@code $SECURITY} + * is <strong>not</strong> reset when {@code $MINOR} is incremented. A + * higher value of {@code $SECURITY} for a given {@code $MAJOR} value, + * therefore, always indicates a more secure release, regardless of the + * value of {@code $MINOR}. </p></li> + * + * </ul> + * + * <p> The fourth and later elements of a version number are free for use + * by downstream consumers of this code base. Such a consumer may, + * <em>e.g.</em>, use the fourth element to identify patch releases which + * contain a small number of critical non-security fixes in addition to + * the security fixes in the corresponding security release. </p> + * + * <p> The version number does not include trailing zero elements; + * <em>i.e.</em>, {@code $SECURITY} is omitted if it has the value zero, + * and {@code $MINOR} is omitted if both {@code $MINOR} and {@code + * $SECURITY} have the value zero. </p> + * + * <p> The sequence of numerals in a version number is compared to another + * such sequence in numerical, pointwise fashion; <em>e.g.</em>, {@code + * 9.9.1} is less than {@code 9.10.3}. If one sequence is shorter than + * another then the missing elements of the shorter sequence are + * considered to be less than the corresponding elements of the longer + * sequence; <em>e.g.</em>, {@code 9.1.2} is less than {@code 9.1.2.1}. + * </p> + * + * <h2><a name="verStr">Version strings</a></h2> + * + * <p> A <em>version string</em>, {@code $VSTR}, consists of a version + * number {@code $VNUM}, as described above, optionally followed by + * pre-release and build information, in the format </p> + * + * <blockquote><pre> + * $VNUM(-$PRE)?(\+($BUILD)?(-$OPT)?)? + * </pre></blockquote> + * + * <p> where: </p> + * + * <ul> + * + * <li><p> <a name="pre">{@code $PRE}</a>, matching {@code ([a-zA-Z0-9]+)} + * --- A pre-release identifier. Typically {@code ea}, for a + * potentially unstable early-access release under active development, + * or {@code internal}, for an internal developer build. + * + * <li><p> <a name="build">{@code $BUILD}</a>, matching {@code + * (0|[1-9][0-9]*)} --- The build number, incremented for each promoted + * build. {@code $BUILD} is reset to {@code 1} when any portion of {@code + * $VNUM} is incremented. </p> + * + * <li><p> <a name="opt">{@code $OPT}</a>, matching {@code + * ([-a-zA-Z0-9\.]+)} --- Additional build information, if desired. In + * the case of an {@code internal} build this will often contain the date + * and time of the build. </p> + * + * </ul> + * + * <p> A version number {@code 10-ea} matches {@code $VNUM = "10"} and + * {@code $PRE = "ea"}. The version number {@code 10+-ea} matches + * {@code $VNUM = "10"} and {@code $OPT = "ea"}. </p> + * + * <p> When comparing two version strings, the value of {@code $OPT}, if + * present, may or may not be significant depending on the chosen + * comparison method. The comparison methods {@link #compareTo(Version) + * compareTo()} and {@link #compareToIgnoreOpt(Version) + * compareToIgnoreOpt()} should be used consistently with the + * corresponding methods {@link #equals(Object) equals()} and {@link + * #equalsIgnoreOpt(Object) equalsIgnoreOpt()}. </p> + * + * <p> A <em>short version string</em>, {@code $SVSTR}, often useful in + * less formal contexts, is a version number optionally followed by a + * pre-release identifier: + * + * <blockquote><pre> + * $VNUM(-$PRE)? + * </pre></blockquote> + * + * @since 9 + */ + public static class Version + implements Comparable<Version> + { + private final List<Integer> version; + private final Optional<String> pre; + private final Optional<Integer> build; + private final Optional<String> optional; + + + // $VNUM(-$PRE)?(\+($BUILD)?(\-$OPT)?)? + // RE limits the format of version strings + // ([1-9][0-9]*(?:(?:\.0)*\.[1-9][0-9]*)*)(?:-([a-zA-Z0-9]+))?(?:(\+)(0|[1-9][0-9]*)?)?(?:-([-a-zA-Z0-9.]+))? + + private static final String VNUM + = "(?<VNUM>[1-9][0-9]*(?:(?:\\.0)*\\.[1-9][0-9]*)*)"; + private static final String VNUM_GROUP = "VNUM"; + + private static final String PRE = "(?:-(?<PRE>[a-zA-Z0-9]+))?"; + private static final String PRE_GROUP = "PRE"; + + private static final String BUILD + = "(?:(?<PLUS>\\+)(?<BUILD>0|[1-9][0-9]*)?)?"; + private static final String PLUS_GROUP = "PLUS"; + private static final String BUILD_GROUP = "BUILD"; + + private static final String OPT = "(?:-(?<OPT>[-a-zA-Z0-9.]+))?"; + private static final String OPT_GROUP = "OPT"; + + private static final String VSTR_FORMAT + = "^" + VNUM + PRE + BUILD + OPT + "$"; + private static final Pattern VSTR_PATTERN = Pattern.compile(VSTR_FORMAT); + + /** + * Constructs a valid <a href="verStr">version string</a> containing + * a <a href="#verNum">version number</a> followed by pre-release and + * build information. + * + * @param s + * A string to be interpreted as a version + * + * @throws IllegalArgumentException + * If the given string cannot be interpreted as a valid + * version + * + * @throws NullPointerException + * If {@code s} is {@code null} + * + * @throws NumberFormatException + * If an element of the version number or the build number + * cannot be represented as an {@link Integer} + */ + private Version(String s) { + if (s == null) + throw new NullPointerException(); + + Matcher m = VSTR_PATTERN.matcher(s); + if (!m.matches()) + throw new IllegalArgumentException("Invalid version string: '" + + s + "'"); + + // $VNUM is a dot-separated list of integers of arbitrary length + List<Integer> list = new ArrayList<>(); + for (String i : m.group(VNUM_GROUP).split("\\.")) + list.add(Integer.parseInt(i)); + version = Collections.unmodifiableList(list); + + pre = Optional.ofNullable(m.group(PRE_GROUP)); + + String b = m.group(BUILD_GROUP); + // $BUILD is an integer + build = (b == null) + ? Optional.<Integer>empty() + : Optional.ofNullable(Integer.parseInt(b)); + + optional = Optional.ofNullable(m.group(OPT_GROUP)); + + // empty '+' + if ((m.group(PLUS_GROUP) != null) && !build.isPresent()) { + if (optional.isPresent()) { + if (pre.isPresent()) + throw new IllegalArgumentException("'+' found with" + + " pre-release and optional components:'" + s + + "'"); + } else { + throw new IllegalArgumentException("'+' found with neither" + + " build or optional components: '" + s + "'"); + } + } + } + + /** + * Parses the given string as a valid <a + * href="#verStr">version string</a> containing a <a + * href="#verNum">version number</a> followed by pre-release and + * build information. + * + * @param s + * A string to interpret as a version + * + * @throws IllegalArgumentException + * If the given string cannot be interpreted as a valid + * version + * + * @throws NullPointerException + * If the given string is {@code null} + * + * @throws NumberFormatException + * If an element of the version number or the build number + * cannot be represented as an {@link Integer} + * + * @return This version + */ + public static Version parse(String s) { + return new Version(s); + } + + /** + * Returns the <a href="#major">major</a> version number. + * + * @return The major version number + */ + public int major() { + return version.get(0); + } + + /** + * Returns the <a href="#minor">minor</a> version number or zero if it + * was not set. + * + * @return The minor version number or zero if it was not set + */ + public int minor() { + return (version.size() > 1 ? version.get(1) : 0); + } + + /** + * Returns the <a href="#security">security</a> version number or zero + * if it was not set. + * + * @return The security version number or zero if it was not set + */ + public int security() { + return (version.size() > 2 ? version.get(2) : 0); + } + + /** + * Returns an unmodifiable {@link java.util.List List} of the + * integer numerals contained in the <a href="#verNum">version + * number</a>. The {@code List} always contains at least one + * element corresponding to the <a href="#major">major version + * number</a>. + * + * @return An unmodifiable list of the integer numerals + * contained in the version number + */ + public List<Integer> version() { + return version; + } + + /** + * Returns the optional <a href="#pre">pre-release</a> information. + * + * @return The optional pre-release information as a String + */ + public Optional<String> pre() { + return pre; + } + + /** + * Returns the <a href="#build">build number</a>. + * + * @return The optional build number. + */ + public Optional<Integer> build() { + return build; + } + + /** + * Returns <a href="#opt">optional</a> additional identifying build + * information. + * + * @return Additional build information as a String + */ + public Optional<String> optional() { + return optional; + } + + /** + * Compares this version to another. + * + * <p> Each of the components in the <a href="#verStr">version</a> is + * compared in the follow order of precedence: version numbers, + * pre-release identifiers, build numbers, optional build information. + * </p> + * + * <p> Comparison begins by examining the sequence of version numbers. + * If one sequence is shorter than another, then the missing elements + * of the shorter sequence are considered to be less than the + * corresponding elements of the longer sequence. </p> + * + * <p> A version with a pre-release identifier is always considered to + * be less than a version without one. Pre-release identifiers are + * compared numerically when they consist only of digits, and + * lexicographically otherwise. Numeric identifiers are considered to + * be less than non-numeric identifiers. </p> + * + * <p> A version without a build number is always less than one with a + * build number; otherwise build numbers are compared numerically. </p> + * + * <p> The optional build information is compared lexicographically. + * During this comparison, a version with optional build information is + * considered to be greater than a version without one. </p> + * + * <p> A version is not comparable to any other type of object. + * + * @param ob + * The object to be compared + * + * @return A negative integer, zero, or a positive integer if this + * {@code Version} is less than, equal to, or greater than the + * given {@code Version} + * + * @throws NullPointerException + * If the given object is {@code null} + */ + @Override + public int compareTo(Version ob) { + return compare(ob, false); + } + + /** + * Compares this version to another disregarding optional build + * information. + * + * <p> Two versions are compared by examining the version string as + * described in {@link #compareTo(Version)} with the exception that the + * optional build information is always ignored. </p> + * + * <p> A version is not comparable to any other type of object. + * + * @param ob + * The object to be compared + * + * @return A negative integer, zero, or a positive integer if this + * {@code Version} is less than, equal to, or greater than the + * given {@code Version} + * + * @throws NullPointerException + * If the given object is {@code null} + */ + public int compareToIgnoreOpt(Version ob) { + return compare(ob, true); + } + + private int compare(Version ob, boolean ignoreOpt) { + if (ob == null) + throw new NullPointerException("Invalid argument"); + + int ret = compareVersion(ob); + if (ret != 0) + return ret; + + ret = comparePre(ob); + if (ret != 0) + return ret; + + ret = compareBuild(ob); + if (ret != 0) + return ret; + + if (!ignoreOpt) + return compareOpt(ob); + + return 0; + } + + private int compareVersion(Version ob) { + int size = version.size(); + int oSize = ob.version().size(); + int min = Math.min(size, oSize); + for (int i = 0; i < min; i++) { + Integer val = version.get(i); + Integer oVal = ob.version().get(i); + if (val != oVal) + return val - oVal; + } + if (size != oSize) + return size - oSize; + return 0; + } + + private int comparePre(Version ob) { + Optional<String> oPre = ob.pre(); + if (!pre.isPresent()) { + if (oPre.isPresent()) + return 1; + } else { + if (!oPre.isPresent()) + return -1; + String val = pre.get(); + String oVal = oPre.get(); + if (val.matches("\\d+")) { + return (oVal.matches("\\d+") + ? (new BigInteger(val)).compareTo(new BigInteger(oVal)) + : -1); + } else { + return (oVal.matches("\\d+") + ? 1 + : val.compareTo(oVal)); + } + } + return 0; + } + + private int compareBuild(Version ob) { + Optional<Integer> oBuild = ob.build(); + if (oBuild.isPresent()) { + return (build.isPresent() + ? build.get().compareTo(oBuild.get()) + : 1); + } else if (build.isPresent()) { + return -1; + } + return 0; + } + + private int compareOpt(Version ob) { + Optional<String> oOpt = ob.optional(); + if (!optional.isPresent()) { + if (oOpt.isPresent()) + return -1; + } else { + if (!oOpt.isPresent()) + return 1; + return optional.get().compareTo(oOpt.get()); + } + return 0; + } + + /** + * Returns a string representation of this version. + * + * @return The version string + */ + @Override + public String toString() { + StringBuilder sb + = new StringBuilder(version.stream() + .map(Object::toString) + .collect(Collectors.joining("."))); + + pre.ifPresent(v -> sb.append("-").append(v)); + + if (build.isPresent()) { + sb.append("+").append(build.get()); + if (optional.isPresent()) + sb.append("-").append(optional.get()); + } else { + if (optional.isPresent()) { + sb.append(pre.isPresent() ? "-" : "+-"); + sb.append(optional.get()); + } + } + + return sb.toString(); + } + + /** + * Determines whether this {@code Version} is equal to another object. + * + * <p> Two {@code Version}s are equal if and only if they represent the + * same version string. + * + * <p> This method satisfies the general contract of the {@link + * Object#equals(Object) Object.equals} method. </p> + * + * @param ob + * The object to which this {@code Version} is to be compared + * + * @return {@code true} if, and only if, the given object is a {@code + * Version} that is identical to this {@code Version} + * + */ + @Override + public boolean equals(Object ob) { + boolean ret = equalsIgnoreOpt(ob); + if (!ret) + return false; + + Version that = (Version)ob; + return (this.optional().equals(that.optional())); + } + + /** + * Determines whether this {@code Version} is equal to another + * disregarding optional build information. + * + * <p> Two {@code Version}s are equal if and only if they represent the + * same version string disregarding the optional build information. + * + * @param ob + * The object to which this {@code Version} is to be compared + * + * @return {@code true} if, and only if, the given object is a {@code + * Version} that is identical to this {@code Version} + * ignoring the optinal build information + * + */ + public boolean equalsIgnoreOpt(Object ob) { + if (this == ob) + return true; + if (!(ob instanceof Version)) + return false; + + Version that = (Version)ob; + return (this.version().equals(that.version()) + && this.pre().equals(that.pre()) + && this.build().equals(that.build())); + } + + /** + * Returns the hash code of this version. + * + * <p> This method satisfies the general contract of the {@link + * Object#hashCode Object.hashCode} method. + * + * @return The hashcode of this version + */ + @Override + public int hashCode() { + int h = 1; + int p = 17; + + h = p * h + version.hashCode(); + h = p * h + pre.hashCode(); + h = p * h + build.hashCode(); + h = p * h + optional.hashCode(); + + return h; + } + } + }
< prev index next >