package org.openlca.core.model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Objects;
/**
* A helper class for handling versions of root entities in openLCA. We support
* the following version scheme major.minor.update but store the parts of the
* version number in a single field. This makes the version number easy to
* compare, automatically increment (the update part), and can be converted to
* the ILCD and ecoinvent version schemes.
*
* For each version field we allow a value between 0 and 32767 so the minimum
* version number is 0.0.0 and the maximum number 32767.32767.32767. The exact
* data type for a version field would be a 2-byte positive integer (short).
* However, we use integers in the public methods of this class to avoid
* casting.
*/
public class Version {
private long value;
public Version() {
this(0);
}
public Version(long value) {
this.value = value;
}
public Version(int major, int minor, int update) {
this.value = 0L;
setParts(major, minor, update);
}
public static long valueOf(int major, int minor, int update) {
return new Version(major, minor, update).value;
}
public static String asString(long version) {
return new Version(version).toString();
}
public int getMajor() {
return (int) ((value >> 32) & 0xffff);
}
public void setMajor(int major) {
setParts(major, getMinor(), getUpdate());
}
/**
* Increments the major part of the version which resets the minor and
* update part to 0.
*/
public void incMajor() {
setParts((getMajor() + 1), 0, 0);
}
public int getMinor() {
return (int) ((value >> 16) & 0xffff);
}
public void setMinor(int minor) {
setParts(getMajor(), minor, getUpdate());
}
/**
* Increments the minor part of the version which resets the update part to
* 0.
*/
public void incMinor() {
setParts(getMajor(), (getMinor() + 1), 0);
}
public int getUpdate() {
return (int) (value & 0xffff);
}
public void setUpdate(int update) {
setParts(getMajor(), getMinor(), update);
}
/**
* Increments the update part of the version. Normally this is automatically
* done by the persistence unit.
*/
public void incUpdate() {
setParts(getMajor(), getMinor(), (getUpdate() + 1));
}
private void setParts(int major, int minor, int update) {
// negative values are not allowed but better we set the first bit to 0.
short clearFirstBit = 0b0111111111111111;
long majorL = (0L | (((short) major) & clearFirstBit)) << 32;
long minorL = (0L | (((short) minor) & clearFirstBit)) << 16;
long updateL = 0L | (((short) update) & clearFirstBit);
value = majorL | minorL | updateL;
}
public long getValue() {
return value;
}
/**
* Returns the version from the given string. The string can be an ILCD
* compatible version string with 3 parts (major.minor.update, e.g.
* 01.01.000) where the two last parts and leading zeros are optional. Thus
* valid version strings are for example: 1, 1.1, 01.01.001, 44.1.96
*/
public static Version fromString(String s) {
if (s == null || s.length() == 0)
return new Version(0);
try {
String[] parts = s.trim().split("\\.");
Version version = new Version(0);
for (int i = 0; i < parts.length; i++)
setPartFromString(i, parts, version);
return version;
} catch (Exception e) {
Logger log = LoggerFactory.getLogger(Version.class);
log.error("failed to parse version " + s, e);
return new Version(0);
}
}
private static void setPartFromString(int i, String[] parts, Version version) {
short p = Short.parseShort(parts[i]);
switch (i) {
case 0:
version.setMajor(p);
break;
case 1:
version.setMinor(p);
break;
case 2:
version.setUpdate(p);
break;
default:
break;
}
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (this == obj)
return true;
if (!obj.getClass().equals(this.getClass()))
return false;
Version other = (Version) obj;
return this.value == other.value;
}
@Override
public int hashCode() {
return Objects.hashCode(value);
}
/**
* Converts the version to an ILCD compatible version string with 3 parts:
* major.minor.update.
*/
@Override
public String toString() {
String major = Integer.toString(getMajor());
if (major.length() == 1)
major = "0" + major;
String minor = Integer.toString(getMinor());
if (minor.length() == 1)
minor = "0" + minor;
String update = Integer.toString(getUpdate());
if (update.length() == 1)
update = "00" + update;
else if (update.length() == 2)
update = "0" + update;
return major + "." + minor + "." + update;
}
}