1 /* 
2  * Copyright 2005 Paul Hinds
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.tp23.antinstaller.runtime;
17
18import java.util.StringTokenizer;
19
20/**
21 * Version helper accepts version numbers of the following format.
22 * [major][clause].[minor][clause].[minor][clause].... ad infinitum
23 * 
24 * If the Java flag is set to true an attempt is made to parse the string as if it were
25 * returned by System.getProperty("java.version");
26 * Since pre 1.3.1 the system is not parsable the default is to accept the string
27 * if there is a format error.
28 * 
29 * For the non java syntax getting the string wrong will result in failed tests
30 * @author teknopaul
31 *
32 */
33public class VersionHelper {
34    
35    public static final String CLAUSE_ALPHA = "alpha";
36    public static final String CLAUSE_BETA = "beta";
37    public static final String CLAUSE_GAMMA = "gamma";
38    public static final String CLAUSE_JAVA_BETA = "ea";
39
40    public boolean equalOrHigher(final String test, final String version) {
41        return equalOrHigher(test, version, false);
42    }
43
44    public boolean majorVersionCompatible(final String test, final String version) {
45        return getMajorVersion(test) == getMajorVersion(version);
46    }
47
48    /**
49     * 
50     * @param test java version string being tested
51     * @param version java version string being used as reference
52     * @param javaSyntax
53     * @return true if the value of <code>test</code> is greater than or equal to the value of <code>version</code>
54     */
55    public boolean equalOrHigher(final String test, final String version, final boolean javaSyntax) {
56        try {
57            StringTokenizer testSt = new StringTokenizer(test, ".");
58            StringTokenizer verSt = new StringTokenizer(version, ".");
59            
60            while (true) {
61                boolean testMore = testSt.hasMoreTokens(); 
62                boolean verMore = verSt.hasMoreTokens();
63                if( ! testMore || ! verMore ){
64                    break;
65                }
66                String testToken = testSt.nextToken();
67                String verToken = verSt.nextToken();
68                short testVer = getVersion(testToken);
69                short versionVer = getVersion(verToken);
70                if( testVer == versionVer ) {
71                    if ( equalClause(getClause( testToken ), getClause(verToken)) ) {
72                        continue;
73                    }
74                    else {
75                        return higherClause(getClause( testToken ), getClause( verToken ), javaSyntax);
76                    }
77                }
78                return testVer > versionVer ;
79            }
80            // equal up to one not having minor details
81            if( countDots(test) >= countDots(version) ){
82                return true;
83            }
84            return test.equals(version);
85        } catch (Exception e) {
86            // syntax exceptions
87            if(javaSyntax){
88                return true; // return true for Java since pre 1.3.1 or other JVMs could get any old rubbish
89            }
90            return false;
91        }
92    }
93    
94    public boolean isValid(final String version) {
95        try {
96            StringTokenizer verSt = new StringTokenizer(version, ".");
97            
98            boolean verMore = false;
99            int i = 0;
00            for (; verMore = verSt.hasMoreTokens(); i++) {
01                
02                String verToken = verSt.nextToken();
03                if("".equals(verToken)){
04                    return false;
05                }
06                // may throw NumberFormatExceptions
07                getVersion(verToken);
08                String clause = getClause(verToken);
09                if( ! "".equals(clause)){
10                    short clauseS = clauseToShort(clause);
11                    if( ! (clauseS == 1 || clauseS == 2 || clauseS == 3 )){
12                        return false;
13                    }
14                }         
15            }
16            if( ! verMore && i == 0) {
17                return false; // nothing there!
18            }
19            return true;
20
21        } 
22        catch (Exception e) {
23            // syntax exceptions
24            return false;
25        }
26    }
27    /**
28     * @return the number part of the clause
29     */
30    private short getVersion(final String section) {
31        StringBuffer sb = new StringBuffer();
32        for (int i = 0; i < section.length(); i++) {
33            char c = section.charAt(i);
34            if(Character.isDigit(c)) {
35                sb.append(c);
36            }
37            else{
38                return Short.parseShort( sb.toString() );
39            }
40        }
41        if(sb.length() > 0) {
42            return Short.parseShort( sb.toString() );
43        }
44        return 0;
45    }
46    
47    /**
48     * @return  the clause eg beta or ""
49     */
50    private String getClause(final String section) {
51        for (int i = 0; i < section.length(); i++) {
52            char c = section.charAt(i);
53            if(Character.isDigit(c)) {
54                continue;
55            }
56            else {
57                return section.substring(i);
58            }
59        }
60        return "";
61    }
62
63    private boolean higherClause(final String test, final String clause, final boolean javaSyntax) {
64        if(javaSyntax) {
65            return clauseJavaToShort(test) > clauseJavaToShort(clause);
66        }
67        else {
68            return clauseToShort(test) > clauseToShort(clause);
69        }
70            
71    }
72    private boolean equalClause(final String test, final String clause) {
73        return clauseToShort(test) == clauseToShort(clause);
74    }
75    
76    private short clauseToShort(String clause) {
77        if(clause.startsWith("-")){
78            clause = clause.substring(1); // knock off java style 1-beta dashes
79        }
80        if( CLAUSE_ALPHA.equals(clause) ) {
81            return 3;
82        }
83        else if( CLAUSE_BETA.equals(clause) ) {
84            return 2;
85        }
86        else if( CLAUSE_GAMMA.equals(clause) ) {
87            return 1;
88        }
89        if(clause.startsWith("_")) { // java build version support 1_03-ea-beta  (discarding the sub sub clause "-ea-beta" because I'm lazy)
90            int hasDash = clause.indexOf('-');
91            if(hasDash > -1) {
92                return Short.parseShort(clause.substring(1, hasDash));
93            }
94            else {
95                return Short.parseShort(clause.substring(1));
96            }
97        }
98        else return Short.MAX_VALUE; // no clause assumes higher
99    }
00    
01    private short clauseJavaToShort(String clause) {
02        if(clause.startsWith("-")){
03            clause = clause.substring(1); // knock off java style 1-beta dashes
04        }
05        else if( CLAUSE_JAVA_BETA.equals(clause) ) {  // -ea early access are assumed to be less good
06            return -2;
07        }
08        if(clause.startsWith("_")) { // java build version support 1_03-ea-beta  (discarding the sub sub clause "-ea-beta" because I'm lazy)
09            int hasDash = clause.indexOf('-');
10            if(hasDash > -1) {
11                return Short.parseShort(clause.substring(1, hasDash));
12            }
13            else {
14                return Short.parseShort(clause.substring(1));
15            }
16        }
17        else return 0; // no clause assumes lower in Java speak
18    }
19
20    private short countDots(final String fullver){
21        short count = 0;
22        for (int i = 0; i < fullver.length(); i++) {
23            if(fullver.charAt(i) == '.') {
24                count++;
25            }
26        }
27        return count;
28    }
29    
30    private short getMajorVersion(String test){
31        return getVersion(test);
32    }
33
34}
35