/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.core.util;
import org.mule.runtime.core.config.MuleManifest;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JdkVersionUtils {
public static final String JAVA_VERSION_PROPERTY = "java.version";
public static class JdkVersion implements Comparable<JdkVersion> {
private Integer major;
private Integer minor;
private Integer micro;
private Integer update;
private String milestone;
public JdkVersion(String jdkVersionStr) {
Matcher m = JDK_VERSION.matcher(jdkVersionStr);
if (m.matches()) {
int numGroups = m.groupCount();
if (numGroups >= 1 && m.group(1) != null && !m.group(1).isEmpty()) {
major = Integer.parseInt(m.group(1));
}
if (numGroups >= 2 && m.group(2) != null && !m.group(2).isEmpty()) {
minor = Integer.parseInt(m.group(2));
}
if (numGroups >= 3 && m.group(3) != null && !m.group(3).isEmpty()) {
micro = Integer.parseInt(m.group(3));
}
if (numGroups >= 4 && m.group(4) != null && !m.group(4).isEmpty()) {
update = Integer.parseInt(m.group(4));
}
if (numGroups >= 5 && m.group(5) != null && !m.group(5).isEmpty()) {
milestone = m.group(5);
}
}
}
public Integer getMajor() {
return major;
}
public Integer getMicro() {
return micro;
}
public String getMilestone() {
return milestone;
}
public Integer getMinor() {
return minor;
}
public Integer getUpdate() {
return update;
}
@Override
public int compareTo(JdkVersion other) {
int comparison = comparePointVersion(getMajor(), other.getMajor());
if (comparison == 0) {
comparison = comparePointVersion(getMinor(), other.getMinor());
if (comparison == 0) {
comparison = comparePointVersion(getMicro(), other.getMicro());
if (comparison == 0) {
comparison = comparePointVersion(getUpdate(), other.getUpdate());
if (comparison == 0) {
comparison = comparePointVersion(getMilestone(), other.getMilestone());
}
}
}
}
return comparison;
}
private <T extends Comparable<T>> int comparePointVersion(T first, T second) {
if (first != null && second != null) {
return first.compareTo(second);
} else if (first != null) {
return 1;
} else if (second != null) {
return -1;
} else {
return 0;
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((major == null) ? 0 : major.hashCode());
result = prime * result + ((micro == null) ? 0 : micro.hashCode());
result = prime * result + ((milestone == null) ? 0 : milestone.hashCode());
result = prime * result + ((minor == null) ? 0 : minor.hashCode());
result = prime * result + ((update == null) ? 0 : update.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof JdkVersion))
return false;
JdkVersion other = (JdkVersion) obj;
if (major == null) {
if (other.major != null)
return false;
} else if (!major.equals(other.major))
return false;
if (micro == null) {
if (other.micro != null)
return false;
} else if (!micro.equals(other.micro))
return false;
if (milestone == null) {
if (other.milestone != null)
return false;
} else if (!milestone.equals(other.milestone))
return false;
if (minor == null) {
if (other.minor != null)
return false;
} else if (!minor.equals(other.minor))
return false;
if (update == null) {
if (other.update != null)
return false;
} else if (!update.equals(other.update))
return false;
return true;
}
}
public static class JdkVersionRange extends VersionRange {
private JdkVersion lower;
private JdkVersion upper;
public JdkVersionRange(String versionRange) {
super(versionRange);
if (!getLowerVersion().isEmpty()) {
lower = new JdkVersion(getLowerVersion());
}
if (!getUpperVersion().isEmpty()) {
upper = new JdkVersion(getUpperVersion());
}
}
public boolean contains(JdkVersion jdkVersion) {
return (lower == null || jdkVersion.compareTo(lower) > 0 || (jdkVersion.compareTo(lower) == 0 && isLowerBoundInclusive()))
&& (upper == null || jdkVersion.compareTo(upper) < 0 || (jdkVersion.compareTo(upper) == 0 && isUpperBoundInclusive()));
}
public boolean isUnder(JdkVersion jdkVersion) {
return (upper != null)
&& (jdkVersion.compareTo(upper) > 0 || (jdkVersion.compareTo(upper) == 0 && !isUpperBoundInclusive()));
}
}
private static final Logger logger = LoggerFactory.getLogger(JdkVersionUtils.class);
/**
* pattern with groups for major, minor, micro, update and milestone (if exists).
* major_version.minor_version.micro_version[_update_version][-milestone]
*/
public static final Pattern JDK_VERSION =
Pattern.compile("^([0-9]+)(?:\\.([0-9]+))?(?:\\.([0-9]+))?(?:_([0-9]+))?(?:-?(.+))?$");
public static List<JdkVersionRange> createJdkVersionRanges(String versionsString) {
Matcher m = VersionRange.VERSION_RANGES.matcher(versionsString);
if (!m.find()) {
throw new IllegalArgumentException("Version range doesn't match pattern: " + VersionRange.VERSION_RANGES.pattern());
}
List<JdkVersionRange> versions = new ArrayList<JdkVersionRange>();
do {
versions.add(new JdkVersionRange(m.group(1)));
} while (m.find());
return versions;
}
public static JdkVersion getJdkVersion() {
return new JdkVersion(System.getProperty(JAVA_VERSION_PROPERTY));
}
public static String getSupportedJdks() {
return MuleManifest.getSupportedJdks();
}
public static boolean isSupportedJdkVendor() {
return SystemUtils.isSunJDK() || SystemUtils.isAppleJDK() || SystemUtils.isIbmJDK();
}
public static String getRecommendedJdks() {
return MuleManifest.getRecommndedJdks();
}
public static boolean isSupportedJdkVersion() {
boolean isSupported = true;
String supportedJdks = getSupportedJdks();
if (supportedJdks != null && !supportedJdks.isEmpty()) {
List<JdkVersionRange> supportedJdkVersionRanges = createJdkVersionRanges(supportedJdks);
isSupported = isJdkInRange(getJdkVersion(), supportedJdkVersionRanges);
}
return isSupported;
}
public static boolean isRecommendedJdkVersion() {
boolean isRecommended = true;
String recommendedJdks = getRecommendedJdks();
if (recommendedJdks != null && !recommendedJdks.isEmpty()) {
List<JdkVersionRange> recommendedJdkVersionRanges = createJdkVersionRanges(recommendedJdks);
isRecommended = isJdkInRange(getJdkVersion(), recommendedJdkVersionRanges);
}
return isRecommended;
}
private static boolean isJdkInRange(JdkVersion version, List<JdkVersionRange> ranges) {
for (JdkVersionRange versionRange : ranges) {
if (versionRange.contains(version)) {
return true;
}
}
return false;
}
private static boolean isJdkAboveRange(JdkVersion version, List<JdkVersionRange> ranges) {
boolean isHigher = true;
for (JdkVersionRange versionRange : ranges) {
isHigher = isHigher && (versionRange.isUnder(version));
}
return isHigher;
}
/**
* Validates that the jdk version and vendor are acceptable values (either supported or not invalid).
*
* @throws RuntimeException if the jdk vendor or version are invalid (known to not work)
*/
public static void validateJdk() throws RuntimeException {
if (!isSupportedJdkVersion()) {
if (isJdkAboveRange(getJdkVersion(), createJdkVersionRanges(getSupportedJdks()))) {
logger.warn("We are looking into adding support for this JDK version. Use it at your own risk.");
} else {
throw new RuntimeException("Unsupported Jdk");
}
}
if (!isSupportedJdkVendor()) {
logger.info("You're executing with a JDK made by a vendor that is not on the recommended list of vendors. Vendor: "
+ SystemUtils.JAVA_VENDOR + " Please consider changing to a recommended JDK vendor.");
}
}
}