/*
* Copyright (c) 2016 OBiBa. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.obiba.runtime;
import java.io.Serializable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Represents a version number and allows comparing to other version numbers.
* <p>
* Format is <code>major'.'minor('.'micro)?(('.'|'-'|'_')qualifier)?</code> <br/>
* where major, minor and micro are composed of digits and qualifier is an arbitrary string.
* </p>
* @author plaflamm
*/
final public class Version implements Comparable<Version>, Serializable {
private static final Pattern VERSION_PATTERN = Pattern.compile("(\\d+)\\.(\\d+)(\\.(\\d+))?(([\\.\\-_])(\\D.+))?");
private static final long serialVersionUID = -7474928316454405471L;
private final int major;
private final int minor;
private final int micro;
@Nonnull
private final String qualifier;
public Version(int major, int minor) {
this(major, minor, 0, null);
}
public Version(int major, int minor, int micro) {
this(major, minor, micro, null);
}
public Version(int major, int minor, int micro, @Nullable String qualifier) {
this.major = major;
this.minor = minor;
this.micro = micro;
this.qualifier = qualifier == null ? "" : qualifier;
}
@SuppressWarnings("LocalVariableHidesMemberVariable")
public Version(String version) {
try {
Matcher m = VERSION_PATTERN.matcher(version);
if(!m.matches()) {
throw invalidVersionString(version, "cannot parse version.");
}
String major = m.group(1);
String minor = m.group(2);
String micro = m.group(4);
String qualifier = m.group(7);
if(major == null || minor == null) {
throw invalidVersionString(version, "major and minor version required");
}
this.major = Integer.parseInt(major);
this.minor = Integer.parseInt(minor);
this.micro = micro == null ? 0 : Integer.parseInt(micro);
this.qualifier = qualifier == null ? "" : qualifier;
} catch(RuntimeException e) {
throw invalidVersionString(version, e);
}
}
@Override
public int compareTo(Version rhs) {
if(major != rhs.major) return major - rhs.major;
if(minor != rhs.minor) return minor - rhs.minor;
if(micro != rhs.micro) return micro - rhs.micro;
return qualifier.compareTo(rhs.qualifier);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder().append(major).append('.').append(minor).append('.').append(micro);
if(qualifier.length() > 0) sb.append('-').append(qualifier);
return sb.toString();
}
@Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(obj == null) return false;
if(getClass() != obj.getClass()) return false;
Version version = (Version) obj;
return major == version.major && minor == version.minor && micro == version.micro &&
qualifier.equals(version.qualifier);
}
@Override
public int hashCode() {
int PRIME = 31;
int hash = 1;
hash = PRIME * hash + major;
hash = PRIME * hash + minor;
hash = PRIME * hash + micro;
hash = PRIME * hash + qualifier.hashCode();
return hash;
}
public int getMajor() {
return major;
}
public int getMinor() {
return minor;
}
public int getMicro() {
return micro;
}
@Nonnull
public String getQualifier() {
return qualifier;
}
private IllegalArgumentException invalidVersionString(String version, String reason) {
return new IllegalArgumentException("Invalid version string '" + version +
"'. Expected format is \"major'.'minor('.'micro)?(('.'|'-'|'_')qualifier)?\": " + reason);
}
private IllegalArgumentException invalidVersionString(String version, Exception e) {
return new IllegalArgumentException("Invalid version string '" + version +
"'. Expected format is \"major'.'minor('.'micro)?(('.'|'-'|'_')qualifier)?\"", e);
}
}