/**
* Copyright 2007-2008 University Of Southern California
*
* Licensed 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 edu.isi.pegasus.common.util;
import edu.isi.pegasus.common.logging.LogManager;
import edu.isi.pegasus.common.logging.LogManagerFactory;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A utility class that allows us to determine condor version.
*
* @author Karan Vahi
*/
public class CondorVersion {
/**
* Predefined Constant for condor version 7.1.0
*/
public static final long v_7_1_0 = CondorVersion.numericValue( "7.1.0" );
/**
* Predefined Constant for condor version 7.1.2
*/
public static final long v_7_1_2 = CondorVersion.numericValue( "7.1.2" );
/**
* Predefined Constant for condor version 7.1.3
*/
public static final long v_7_1_3 = CondorVersion.numericValue( "7.1.3" );
/**
* Predefined Constant for condor version 8.3.6
*/
public static final long v_8_3_6 = CondorVersion.numericValue( "8.3.6" );
/**
* Predefined Constant for condor version 8.5.6
*/
public static final long v_8_5_6 = CondorVersion.numericValue( "8.5.6" );
/**
* The maximum number of components version can have. MAJOR, MINOR, PATCH
*/
private static final int MAX_NUMBER_OF_VERSION_COMPONENTS = 3;
/**
* The maximum number of digits each component of version can have.
*/
private static final int MAX_VERSION_PRECISION = 2;
/**
* The condor version command to be executed.
*/
public static final String CONDOR_VERSION_COMMAND = "condor_version";
/**
* Store the regular expressions necessary to parse the output of
* condor_version. The rule for the format is
*
* $CondorVersion: 7.4.1 Dec 17 2009 <ANY_ARBITRARY_STRING> $
* where <ANY_ARBITRARY_STRING> may or may not be there, and can include spaces but is
* really completely arbitrary.
*
* e.g. $CondorVersion: 7.1.0 Apr 1 2008 BuildID: 80895$
*/
private static final String mRegexExpression =
// "\\$CondorVersion:\\s*([0-9][\\.][0-9][\\.][0-9])[a-zA-Z:0-9\\s]*\\$";
//"\\$CondorVersion:\\s*([0-9][\\.][0-9][\\.][0-9])[\\w\\W\\s]*\\$";
"\\$CondorVersion:\\s*([0-9][\\.][0-9][\\.][0-9])[\\p{ASCII}\\s]*\\$";
/**
* Stores compiled patterns at first use, quasi-Singleton.
*/
private static Pattern mPattern = null;
/**
* Converts a string into the corresponding integer value.
*
* @param version
*
* @return int value of the version, else -1 in case of null version
* or incorrect formatted string
*
* @deprecated
*/
public static int intValue( String version ){
int result = 0;
if( version == null ){
return -1;
}
//split on .
try{
String[] subs = version.split( "\\." );
int index = subs.length;
for( int i = 0, y = subs.length - 1; y >= 0; y--,i++){
result += (int) (Math.pow(10, y) * (Integer.parseInt(subs[i])));
}
}
catch( NumberFormatException nfe ){
result = -1;
}
return result;
}
/**
* Converts a string into the corresponding numeric value.
*
* @param version in form of major.minor.patch. You can opt to omit the
* minor and patch versions if you want
*
* @return float value of the version, else -1 in case of null version
* or incorrect formatted string
*/
public static long numericValue( String version ){
long result = 0;
if( version == null ){
return -1;
}
//we are converting to XX.XX.XX
//add extra padding that is leading zero if only one digit
char[] arr = new char[6];
//split on .
try{
String[] subs = version.split( "\\." );
int y = subs.length;
if ( y > CondorVersion.MAX_NUMBER_OF_VERSION_COMPONENTS ){
throw new IllegalArgumentException(
"Only version numbers with max two dots are accepted i.e ( MAJOR.MINOR.PATCH ) " + version );
}
int i = 0;
//for each sub convert to a two digit form
for( int z = 0; z < y; z++ ){
//compute the sub length
int len = subs[z].length();
if( len > CondorVersion.MAX_VERSION_PRECISION ){
throw new IllegalArgumentException( "Only two digit precision is allowed in version numbers " + version);
}
//add leading zeros if required
for ( int d = CondorVersion.MAX_VERSION_PRECISION - len; d > 0; d--){
arr[i++] = '0';
}
//copy into arr the sub[z]
for( int d = 0; d < len; d++){
char ch = subs[z].charAt( d );
if( !Character.isDigit(ch) ){
throw new IllegalArgumentException( "Non digit specified in version " + version);
}
arr[i++] = ch;
}
}
//add trailing zeroes if required
while( i < 6 ){
arr[i++] = '0';
}
}
catch( NumberFormatException nfe ){
result = -1;
}
return Long.parseLong( new String(arr) );
}
/**
* The default logger.
*/
private LogManager mLogger;
/**
* Factory method to instantiate the class.
*
* @return instance to the class
*/
public static CondorVersion getInstance( ){
return getInstance( null );
}
/**
* Factory method to instantiate the class.
*
*
* @param logger the logger object
*
* @return instance to the class.
*/
public static CondorVersion getInstance( LogManager logger ){
if( logger == null ){
logger = LogManagerFactory.loadSingletonInstance();
}
return new CondorVersion( logger );
}
/**
* The default constructor.
*
* @param logger the logger object
*/
private CondorVersion( LogManager logger ){
mLogger = logger;
if( mPattern == null ){
mPattern = Pattern.compile( mRegexExpression );
}
}
/**
* Returns the condor version parsed by executing the condor_version
* command.
*
* @return the version number as int else -1 if unable to determine.
*/
public long numericValue(){
long result = -1;
try{
result = CondorVersion.numericValue( version() );
}
catch( Exception e ){
mLogger.log("Exception while parsing condor_version ", e,
LogManager.ERROR_MESSAGE_LEVEL);
}
return result;
}
/**
* Returns the condor version parsed by executing the condor_version
* command.
*
* @return the version number as String else null if unable to determine.
*/
public String version(){
String version = null;
try{
//set the callback and run the grep command
CondorVersionCallback c = new CondorVersionCallback( );
Runtime r = Runtime.getRuntime();
Process p = r.exec( CONDOR_VERSION_COMMAND );
//Process p = r.exec( CONDOR_VERSION_COMMAND );
//spawn off the gobblers
StreamGobbler ips = new StreamGobbler(p.getInputStream(), c);
StreamGobbler eps = new StreamGobbler(p.getErrorStream(),
new StreamGobblerCallback(){
//we cannot log to any of the default stream
LogManager mLogger = this.mLogger;
public void work(String s){
mLogger.log("Output on stream gobller error stream " +
s,LogManager.DEBUG_MESSAGE_LEVEL);
}
});
ips.start();
eps.start();
//wait for the threads to finish off
ips.join();
version = c.getVersion();
eps.join();
//get the status
int status = p.waitFor();
if( status != 0){
mLogger.log("Command " + CONDOR_VERSION_COMMAND + " exited with status " + status,
LogManager.WARNING_MESSAGE_LEVEL);
}
}
catch(IOException ioe){
mLogger.log("IOException while determining condor_version ", ioe,
LogManager.ERROR_MESSAGE_LEVEL);
}
catch( InterruptedException ie){
//ignore
}
mLogger.log( "Condor Version as string " + version, LogManager.DEBUG_MESSAGE_LEVEL );
return version;
}
/**
* An inner class, that implements the StreamGobblerCallback to determine
* the version of Condor being used.
*
*/
private static class CondorVersionCallback implements StreamGobblerCallback{
/**
* The version detected.
*/
private String mVersion;
/**
* The Default Constructor
*/
public CondorVersionCallback( ){
mVersion = null;
}
/**
* Callback whenever a line is read from the stream by the StreamGobbler.
* Counts the occurences of the word that are in the line, and
* increments to the global counter.
*
* @param line the line that is read.
*/
public void work( String line ){
Matcher matcher = mPattern.matcher( line );
if( matcher.matches( ) ){
mVersion = matcher.group( 1 );
}
}
/**
* Returns the condor version detected.
*
* @return the condor version else null
*/
public String getVersion(){
return mVersion;
}
}
/**
* The main program to test.
*
* @param args
*/
public static void main( String[] args ){
LogManager logger = LogManagerFactory.loadSingletonInstance();
CondorVersion cv = CondorVersion.getInstance();
logger.logEventStart( "CondorVersion", "CondorVersion", "Version");
System.out.println( "Condor Version is " + cv.version() );
System.out.println( "10.0.0 is " + CondorVersion.numericValue( "10.0.0") );
System.out.println( "7.1.2 is " + CondorVersion.numericValue( "7.1.2") );
System.out.println( "7.1.18 is " + CondorVersion.numericValue( "7.1.18" ) );
System.out.println( "7.1.19 is " + CondorVersion.numericValue( "7.1.19" ) );
System.out.println( "6.99.9 is " + CondorVersion.numericValue( "6.99.9" ) );
System.out.println( "7 is " + CondorVersion.numericValue( "7.2.2" ) );
logger.logEventCompletion();
//some sanity checks on the Regex
String version = "$CondorVersion: 7.4.1 Dec 17 2009 UWCS-PRE $";
Matcher matcher = cv.mPattern.matcher( version );
if( matcher.matches() ){
System.out.println( "Version for " + version + " is " + matcher.group( 1 ));
}
version = "$CondorVersion: 7.4.1 Dec 17 2009 BuildID: 204351 $";
matcher = cv.mPattern.matcher( version );
if( matcher.matches() ){
System.out.println( "Version for " + version + " is " + matcher.group( 1 ));
}
}
}