/* * Copyright (C) 2011 Laurent Caillette * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * 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.novelang; import java.util.Comparator; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Represents a version number with the "major + minor + fix" scheme, and also the version * of the whole application. * By default the version is "SNAPSHOT" and the build process replaces a magic string by the * version number of the release. * In order to replace the magic string at build time, this class compiles separately so it * shouldn't depend on other Novelang classes. * * @author Laurent Caillette */ public final class Version { private final boolean snapshot ; private final int major ; private final int minor ; private final int fix ; private Version() { snapshot = true ; this.major = -999 ; this.minor = -999 ; this.fix = -999 ; } public Version( final int major, final int minor, final int fix ) { checkArgument( "major number should be >= 0, it is " + major, major >= 0 ) ; checkArgument( "minor number should be >= 0, it is " + minor, minor >= 0 ) ; checkArgument( "fix number should be >= 0, it is " + fix, fix >= 0 ) ; snapshot = false ; this.major = major ; this.minor = minor ; this.fix = fix ; } /** * Replaces {@link com.google.common.base.Preconditions} because when rebuilding the class * with modified {@link #PRODUCT_VERSION_AS_STRING} we don't want to carry additional * dependencies. */ private static void checkArgument( final String message, final boolean condition ) { if( ! condition ) { throw new IllegalArgumentException( message ) ; } } public int getMajor() { verifyNotSnapshot() ; return major ; } public int getMinor() { verifyNotSnapshot() ; return minor ; } public int getFix() { verifyNotSnapshot() ; return fix ; } private void verifyNotSnapshot() { if( isSnapshot() ) { throw new IllegalStateException( "snapshot version" ) ; } } /** * This very string is replaced by the official version number by the build script. */ private static final String PRODUCT_VERSION_AS_STRING = "${project.version}" ; /** * Current version, reflects changes performed by build script. */ public static final Version CURRENT_PRODUCT_VERSION ; /** * This initialization must happen before parsing the version, otherwise we hit * a {@code NullPointerException}. */ private static final Pattern PATTERN = Pattern.compile( "(\\d+)\\.(\\d+)\\.(\\d+)" ) ; static { try { CURRENT_PRODUCT_VERSION = parse( PRODUCT_VERSION_AS_STRING ) ; } catch ( VersionFormatException e ) { throw new RuntimeException( e ) ; } } private static final String SNAPSHOT_NAME = "SNAPSHOT" ; public static final Version SNAPSHOT = new Version() ; public boolean isSnapshot() { return snapshot ; } public String getName() { return isSnapshot() ? SNAPSHOT_NAME : major + "." + minor + "." + fix ; } public static Version parse( final String s ) throws VersionFormatException { if( ( "${" + "project.version" + "}" ).equals( s ) || SNAPSHOT_NAME.equals( s ) ) { return new Version() ; } else { final Matcher matcher = PATTERN.matcher( s ) ; if( matcher.find() ) { final int major = Integer.parseInt( matcher.group( 1 ) ) ; final int minor = Integer.parseInt( matcher.group( 2 ) ) ; final int fix = Integer.parseInt( matcher.group( 3 ) ) ; return new Version( major, minor, fix ) ; } else { throw new VersionFormatException( s ) ; } } } /** * Compares two {@code Version} objects on their numbers; a SNAPSHOT is considered as the * greater (most recent). */ public static final Comparator< Version > COMPARATOR = new Comparator< Version >() { /** * Compares its two arguments for order. Returns a negative integer, zero, or a positive * integer as the first argument is less than, equal to, or greater than the second. */ @Override public int compare( final Version version1, final Version version2 ) { if( version1 == version2 ) { return 0 ; } if( version1 == null ) { return -1 ; } if( version2 == null ) { return 1 ; } if( version1.isSnapshot() ) { if( version2.isSnapshot() ) { return 0 ; } else { return 1 ; } } else if( version2.isSnapshot() ) { return -1 ; } final int majorDifference = version1.getMajor() - version2.getMajor() ; if( majorDifference == 0 ) { final int minorDifference = version1.getMinor() - version2.getMinor() ; if( minorDifference == 0 ) { return version1.getFix() - version2.getFix() ; } else { return minorDifference ; } } else { return majorDifference ; } } } ; }