blob: 94e4d3ade939a9c30116b9c16879b7f52943818c [file] [log] [blame]
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.baidu.hugegraph.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
public final class VersionUtil {
/**
* Compare if a version is inside a range [begin, end)
* @param version The version to be compared
* @param begin The lower bound of the range
* @param end The upper bound of the range
* @return true if belong to the range, otherwise false
*/
public static boolean match(Version version, String begin, String end) {
E.checkArgumentNotNull(version, "The version to match is null");
return version.compareTo(new Version(begin)) >= 0 &&
version.compareTo(new Version(end)) < 0;
}
/**
* Compare if a version is greater than the other one (inclusive)
* @param version The version to be compared
* @param other The lower bound of the range
* @return true if it's greater than the other, otherwise false
*/
public static boolean gte(String version, String other) {
E.checkArgumentNotNull(version, "The version to match is null");
return new Version(version).compareTo(new Version(other)) >= 0;
}
/**
* Check whether a component version is matched expected range,
* throw an exception if it's not matched.
* @param version The version to be checked
* @param begin The lower bound of the range
* @param end The upper bound of the range
* @param component The owner component of version
*/
public static void check(Version version, String begin, String end,
String component) {
E.checkState(VersionUtil.match(version, begin, end),
"The version %s of '%s' is not in [%s, %s)",
version, component, begin, end);
}
/**
* Get implementation version from manifest in jar
* @param clazz The class to be load from jar package
* @return The implementation version
*/
public static String getImplementationVersion(Class<?> clazz) {
/*
* We don't use Package.getImplementationVersion() due to
* a duplicate package would override the origin package info.
* https://stackoverflow.com/questions/1272648/reading-my-own-jars-manifest
*/
String className = clazz.getSimpleName() + ".class";
String classPath = clazz.getResource(className).toString();
if (!classPath.startsWith("jar:file:")) {
// Class not from JAR
return null;
}
int offset = classPath.lastIndexOf("!");
assert offset > 0;
// Get manifest file path
String manifestPath = classPath.substring(0, offset + 1);
return getImplementationVersion(manifestPath);
}
public static String getImplementationVersion(String manifestPath) {
manifestPath += "/META-INF/MANIFEST.MF";
Manifest manifest = null;
try {
manifest = new Manifest(new URL(manifestPath).openStream());
} catch (IOException ignored) {
return null;
}
return manifest.getMainAttributes()
.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
}
/**
* Get version from pom.xml
* @return The pom version
*/
public static String getPomVersion() {
String cmd = "mvn help:evaluate -Dexpression=project.version " +
"-q -DforceStdout";
Process process = null;
InputStreamReader isr = null;
try {
process = Runtime.getRuntime().exec(cmd);
process.waitFor();
isr = new InputStreamReader(process.getInputStream());
BufferedReader br = new BufferedReader(isr);
return br.readLine();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (isr != null) {
try {
isr.close();
} catch (Exception ignored) {
// pass
}
}
// Destroy child process
if (process != null) {
process.destroy();
}
}
}
/**
* class Version for compare
* https://stackoverflow.com/questions/198431/how-do-you-compare-two-version-strings-in-java
*/
public static class Version implements Comparable<Version> {
public static Version of(Class<?> clazz) {
return Version.of(clazz, null);
}
public static Version of(Class<?> clazz, String defaultValue) {
String v = getImplementationVersion(clazz);
if (v == null) {
v = defaultValue;
}
return v == null ? null : new Version(v);
}
public static Version of(String version) {
return new Version(version);
}
/************************** Version define **************************/
private final String version;
private final int[] parts;
public Version(String version) {
E.checkArgumentNotNull(version, "The version is null");
E.checkArgument(version.matches("[0-9]+(\\.[0-9]+)*"),
"Invalid version format: %s", version);
this.version = version;
this.parts = parseVersion(version);
}
private static int[] parseVersion(String version) {
String[] parts = version.split("\\.");
int[] partsNumber = new int[parts.length];
for (int i = 0; i < parts.length; i++) {
partsNumber[i] = Integer.parseInt(parts[i]);
}
return partsNumber;
}
public final String get() {
return this.version;
}
@Override
public int compareTo(Version that) {
if (that == null) {
return 1;
}
int[] thisParts = this.parts;
int[] thatParts = that.parts;
int length = Math.max(thisParts.length, thatParts.length);
for (int i = 0; i < length; i++) {
int thisPart = i < thisParts.length ? thisParts[i] : 0;
int thatPart = i < thatParts.length ? thatParts[i] : 0;
if (thisPart < thatPart) {
return -1;
}
if (thisPart > thatPart) {
return 1;
}
}
return 0;
}
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (this.getClass() != that.getClass()) {
return false;
}
return this.compareTo((Version) that) == 0;
}
@Override
public int hashCode() {
int hash = 0;
for (int i = this.parts.length - 1; i >= 0; i--) {
int part = this.parts[i];
if (part == 0 && hash == 0) {
continue;
}
hash = 31 * hash + Integer.hashCode(part);
}
return hash;
}
@Override
public String toString() {
return this.version;
}
}
}