package org.jboss.loom.recog;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Ondrej Zizka, ozizka at redhat.com
*/
public final class VersionComparer {
private static final Logger log = LoggerFactory.getLogger( VersionComparer.class.getName() );
/**
* Strings after release: SP, CP
* Strings for release: GA, GOLD, Final, 0
* Latest before release: SNAPSHOT
* Before release: (any other)
* @param s
* @return
*/
private static int getStringLevel( String s ){
if( "SP".equalsIgnoreCase(s) || "CP".equalsIgnoreCase(s) )
return 1;
if( "GA".equalsIgnoreCase(s) || "GOLD".equalsIgnoreCase(s) || "Final".equalsIgnoreCase(s) || "0".equals(s) )
return 0;
if( "SNAPSHOT".equalsIgnoreCase(s) )
return -1;
return -2;
}
/**
* Compares two string parts of the version string, e.g. "GA" vs. "SNAPSHOT".
* @returns like compareTo() does.
*/
public static int compareStrings( String a, String b ){
int aLev = getStringLevel( a );
int bLev = getStringLevel( b );
if( aLev == bLev )
return a.compareToIgnoreCase(b);
else
return aLev - bLev;
}
/**
* Compares two version strings, like compareTo() does.
* TODO: Maven comparison algorithm works bad; Code own one.
*
* Strings after release: SP, CP
* Strings for release: GA, GOLD
* Latest before release: SNAPSHOT
* Before release: (any other)
*/
public static int compareVersions(String aStr, String bStr){
log.debug( String.format(" ----- Comparing versions: %s and %s ... ------ ", aStr, bStr) );
final String[] aParts = StringUtils.split(aStr.toUpperCase(), ".-_");
final String[] bParts = StringUtils.split(bStr.toUpperCase(), ".-_");
//log.debug( String.format(" aLen = %d, bLen = %d", aParts.length, bParts.length) );
int aOff = 0;
int bOff = 0;
//int longer = 0;
//for( int i = v1parts.length-1; i >= 0; i--){ }
parts: do {
boolean aIsLast = aOff >= aParts.length - 1;
boolean bIsLast = bOff >= bParts.length - 1;
String a = aParts[aOff];
String b = bParts[bOff];
// a pseudo-loop - just to use "continue".
thisPart: do {
if( StringUtils.equals(a, b) )
continue;
log.debug( String.format("A[%d] = '%s', B[%d] = '%s'", aOff, a, bOff, b) );
if( "GA".equals(a) ) a = "0";
if( "GA".equals(b) ) b = "0";
boolean aIsNum = NumberUtils.isDigits( a );
boolean bIsNum = NumberUtils.isDigits( b );
Integer aNum = aIsNum ? NumberUtils.createInteger( a ) : null;
Integer bNum = bIsNum ? NumberUtils.createInteger( b ) : null;
log.debug( String.format("A[%d] = '%s', B[%d] = '%s'", aOff, a, bOff, b) );
if( aIsNum && bIsNum ){
log.debug("aIsNum && bIsNum");
int diff = aNum - bNum;
// Different numbers - return the diff.
if( diff != 0 ) return diff;
// The same numbers - skip to next position.
break thisPart;
}
else if( aIsNum ^ bIsNum ){
log.debug("aIsNum ^ bIsNum");
if( aIsNum ){
// Skip aditional "decimal" zeros - e.g. 2.0.0.FOO vs. 2.0.BAR .
if ( aNum == 0 ){
if( ! aIsLast ){ aOff++; continue parts; }
return compareStrings("0", b); // or: +getStringLevel(a);
}
return 1;
}
else /* vice versa for ( bIsNum ) */ {
// Skip aditional "decimal" zeros - e.g. 2.0.0.FOO vs. 2.0.BAR .
if ( bNum == 0 ){
if( ! bIsLast ){ bOff++; continue parts; }
return compareStrings(a, "0"); // or: -getStringLevel(b);
}
return -1;
}
}
// Neither is a number -> Compare two strings.
{
// CP - cumulative patch - is bigger than other strings. SP should be far enough in the alphabet.
// (There is a need for standardized project versioning strings.)
//if( "CP".equals(a) ) a = "SP";
//if( "CP".equals(b) ) b = "SP";
log.debug("Comparing strings produces" + compareStrings(a, b) );
int strDiff = compareStrings(a, b);
if( strDiff != 0 )
return strDiff;
}
} while( false ); // label thisPart:
// Advance to the next part, unless we're at the last one..
//if( aOff < aParts.length -1 ) aOff++;
//if( bOff < bParts.length -1 ) bOff++;
log.debug( String.format("Incrementing... %s %s", aIsLast, bIsLast) );
if( ! aIsLast ) aOff++;
if( ! bIsLast ) bOff++;
if( aIsLast && bIsLast ) break;
// End when we reached the last parts of both versions.
} while ( true );
//} while( aOff < aParts.length -1 || bOff < bParts.length -1 );
log.debug("Reached comparison loop end.");
return 0; // TODO: Fix
/*
// Maven's algorithm.
DefaultArtifactVersion v1 = new DefaultArtifactVersion(v1s);
DefaultArtifactVersion v2 = new DefaultArtifactVersion(v2s);
return v1.compareTo(v2);
/**/
}// compareVersions();
}// class