io.microsphere.util.Version Maven / Gradle / Ivy
The newest version!
/*
* 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 io.microsphere.util;
import io.microsphere.lang.ClassDataRepository;
import io.microsphere.util.jar.JarUtils;
import javax.annotation.Nonnull;
import java.net.URL;
import java.util.Objects;
import java.util.StringTokenizer;
import java.util.function.BiPredicate;
import static io.microsphere.constants.SymbolConstants.EQUAL;
import static io.microsphere.constants.SymbolConstants.GREATER_THAN;
import static io.microsphere.constants.SymbolConstants.GREATER_THAN_OR_EQUAL_TO;
import static io.microsphere.constants.SymbolConstants.LESS_THAN;
import static io.microsphere.constants.SymbolConstants.LESS_THAN_OR_EQUAL_TO;
import static io.microsphere.text.FormatUtils.format;
import static io.microsphere.util.Version.Operator.EQ;
import static io.microsphere.util.Version.Operator.GE;
import static io.microsphere.util.Version.Operator.GT;
import static io.microsphere.util.Version.Operator.LE;
import static io.microsphere.util.Version.Operator.LT;
import static java.lang.Integer.compare;
/**
* The value object to represent a version consisting of major, minor and patch part.
*
* @author Mercy
* @since 1.0.0
*/
public class Version implements Comparable {
private final int major;
private final int minor;
private final int patch;
public Version(int major) {
this(major, 0);
}
public Version(int major, int minor) {
this(major, minor, 0);
}
public Version(int major, int minor, int patch) {
this.major = major;
this.minor = minor;
this.patch = patch;
}
public static Version of(int major) {
return new Version(major);
}
public static Version of(int major, int minor) {
return new Version(major, minor);
}
public static Version of(int major, int minor, int patch) {
return new Version(major, minor, patch);
}
public static Version of(String version) {
if (version == null) {
throw new NullPointerException("The 'version' argument must not be null!");
}
version = version.trim();
if (version.isEmpty()) {
throw new IllegalArgumentException("The 'version' argument must not be blank!");
}
StringTokenizer st = new StringTokenizer(version, ".");
int major = getValue(st);
int minor = getValue(st);
int patch = getValue(st);
return of(major, minor, patch);
}
/**
* Class that exposes the version. Fetches the "Implementation-Version" manifest attribute from the jar file.
*
* @param targetClass the class to exposes the version
* @return non-null
*/
@Nonnull
public static Version getVersion(Class> targetClass) {
Package targetPackage = targetClass.getPackage();
String version = targetPackage.getImplementationVersion();
if (version == null) {
ClassDataRepository repository = ClassDataRepository.INSTANCE;
URL classResource = repository.getCodeSourceLocation(targetClass);
String jarFilePath = JarUtils.resolveRelativePath(classResource);
String errorMessage = format("The \"Implementation-Version\" manifest attribute can't be fetched from " + "the jar file[path : '{}'] by the target class[name :'{}']", jarFilePath, targetClass.getName());
throw new IllegalArgumentException(errorMessage);
}
return of(version);
}
static int getValue(StringTokenizer st) {
if (st.hasMoreTokens()) {
return getValue(st.nextToken());
}
return 0;
}
static int getValue(String part) {
final int value;
try {
value = Integer.parseInt(part);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("The 'version' argument contains the non-number part : " + part, e);
}
return value;
}
/**
* The major version
*
* @return major version
*/
public int getMajor() {
return major;
}
/**
* The minor version
*
* @return minor version
*/
public int getMinor() {
return minor;
}
/**
* The patch
*
* @return patch
*/
public int getPatch() {
return patch;
}
/**
* Current {@link Version} is greater than that
*
* @param that the version to be compared
* @return true
if greater than, or false
* @see #isGreaterThan(Version)
*/
public boolean gt(Version that) {
return isGreaterThan(that);
}
/**
* Current {@link Version} is greater than that
*
* @param that the version to be compared
* @return true
if greater than, or false
* @see #gt(Version)
*/
public boolean isGreaterThan(Version that) {
return GT.test(this, that);
}
/**
* Current {@link Version} is greater than or equal to that
*
* @param that the version to be compared
* @return true
if greater than, or false
* @see #isGreaterOrEqual(Version)
*/
public boolean ge(Version that) {
return isGreaterOrEqual(that);
}
/**
* Current {@link Version} is greater than or equal to that
*
* @param that the version to be compared
* @return true
if greater than, or false
* @see #ge(Version)
*/
public boolean isGreaterOrEqual(Version that) {
return GE.test(this, that);
}
/**
* Current {@link Version} is less than that
*
* @param that the version to be compared
* @return true
if less than, or false
*/
public boolean lt(Version that) {
return isLessThan(that);
}
/**
* Current {@link Version} is less than that
*
* @param that the version to be compared
* @return true
if less than, or false
*/
public boolean isLessThan(Version that) {
return LT.test(this, that);
}
/**
* Current {@link Version} is less than or equal to that
*
* @param that the version to be compared
* @return true
if less than, or false
* @see #isLessOrEqual(Version)
*/
public boolean le(Version that) {
return isLessOrEqual(that);
}
/**
* Current {@link Version} is less than or equal to that
*
* @param that the version to be compared
* @return true
if less than, or false
* @see #le(Version)
*/
public boolean isLessOrEqual(Version that) {
return LE.test(this, that);
}
/**
* Current {@link Version} is equal to that
*
* @param that the version to be compared
* @return true
if equals, or false
*/
public boolean eq(Version that) {
return this.equals(that);
}
/**
* Current {@link Version} is equal to that
*
* @param that the version to be compared
* @return true
if equals, or false
*/
public boolean equals(Version that) {
return EQ.test(this, that);
}
/**
* Current {@link Version} is equal to that
*
* @param o the version to be compared
* @return true
if equals, or false
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Version)) return false;
Version version = (Version) o;
return equals(version);
}
@Override
public int hashCode() {
int result = major;
result = 31 * result + minor;
result = 31 * result + patch;
return result;
}
@Override
public int compareTo(Version that) {
int result = compare(this.major, that.major);
if (result != 0) {
return result;
}
result = compare(this.minor, that.minor);
if (result != 0) {
return result;
}
result = compare(this.patch, that.patch);
return result;
}
@Override
public String toString() {
String sb = "Version{" + "major=" + major +
", minor=" + minor +
", patch=" + patch +
'}';
return sb;
}
public enum Operator implements BiPredicate {
/**
* The Operator : "Equal to"
*/
EQ(EQUAL) {
@Override
public boolean test(Version v1, Version v2) {
if (v1 == v2) {
return true;
}
if (v2 == null) return false;
if (v1.major != v2.major) return false;
if (v1.minor != v2.minor) return false;
return v1.patch == v2.patch;
}
},
/**
* The Operator : "Less than"
*/
LT(LESS_THAN) {
@Override
public boolean test(Version v1, Version v2) {
if (v1 == v2) {
return true;
}
if (v2 == null) return false;
return v1.compareTo(v2) < 0;
}
},
/**
* The Operator : "Less than or equal to"
*/
LE(LESS_THAN_OR_EQUAL_TO) {
@Override
public boolean test(Version v1, Version v2) {
if (v1 == v2) {
return true;
}
if (v2 == null) return false;
return v1.compareTo(v2) <= 0;
}
},
/**
* The Operator : "Greater than"
*/
GT(GREATER_THAN) {
@Override
public boolean test(Version v1, Version v2) {
if (v1 == v2) {
return true;
}
if (v2 == null) return false;
return v1.compareTo(v2) > 0;
}
},
/**
* The Operator : "Greater than or equal to"
*/
GE(GREATER_THAN_OR_EQUAL_TO) {
@Override
public boolean test(Version v1, Version v2) {
if (v1 == v2) {
return true;
}
if (v2 == null) return false;
return v1.compareTo(v2) >= 0;
}
};
private final String symbol;
Operator(String symbol) {
this.symbol = symbol;
}
/**
* Find the symbol to an {@link Operator} member if possible
*
* @param symbol the operators' symbol
* @return null
if can't be found
*/
public static Operator of(String symbol) {
for (Operator operator : values()) {
if (Objects.equals(symbol, operator.symbol)) {
return operator;
}
}
throw new IllegalArgumentException(format("The Operator can't be parsed by the symbol '{}'!", symbol));
}
}
}