001    /*--------------------------------------------------------------------------+
002    $Id: Version.java 26283 2010-02-18 11:18:57Z juergens $
003    |                                                                          |
004    | Copyright 2005-2010 Technische Universitaet Muenchen                     |
005    |                                                                          |
006    | Licensed under the Apache License, Version 2.0 (the "License");          |
007    | you may not use this file except in compliance with the License.         |
008    | You may obtain a copy of the License at                                  |
009    |                                                                          |
010    |    http://www.apache.org/licenses/LICENSE-2.0                            |
011    |                                                                          |
012    | Unless required by applicable law or agreed to in writing, software      |
013    | distributed under the License is distributed on an "AS IS" BASIS,        |
014    | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
015    | See the License for the specific language governing permissions and      |
016    | limitations under the License.                                           |
017    +--------------------------------------------------------------------------*/
018    package edu.tum.cs.commons.version;
019    
020    import java.io.Serializable;
021    import java.util.regex.Matcher;
022    import java.util.regex.Pattern;
023    
024    import edu.tum.cs.commons.error.FormatException;
025    
026    /**
027     * A class to describe versions of software (or other) artifacts. A version has
028     * a major and a minor version number. Version are ordered. This class is
029     * immutable.
030     * 
031     * @author Florian Deissenboeck
032     * @author $Author: juergens $
033     * @version $Rev: 26283 $
034     * @levd.rating GREEN Hash: 9B19160CC477DC98C73F68A0DCD4C759
035     */
036    public class Version implements Comparable<Version>, Serializable {
037    
038            /** Major version. */
039            private final int major;
040    
041            /** Minor version. */
042            private final int minor;
043    
044            /**
045             * Create a new version.
046             * 
047             * @param major
048             *            major version number.
049             * @param minor
050             *            minor version number.
051             * @throws IllegalArgumentException
052             *             if one of the version numbers is less than 0.
053             */
054            public Version(int major, int minor) {
055    
056                    if (major < 0 || minor < 0) {
057                            throw new IllegalArgumentException(
058                                            "Versions may not be less than 0.");
059                    }
060    
061                    this.major = major;
062                    this.minor = minor;
063            }
064    
065            /**
066             * Parses a version from a string. The format has to be "major.minor".
067             * 
068             * @throws FormatException
069             *             if the string does not follow the expected pattern.
070             */
071            public static Version parseVersion(String s) throws FormatException {
072                    Matcher m = Pattern.compile("\\s*(\\d+)\\.(\\d+)\\s*").matcher(s);
073                    if (!m.matches()) {
074                            throw new FormatException(
075                                            "The provided string did not match the pattern!");
076                    }
077                    return new Version(Integer.parseInt(m.group(1)), Integer.parseInt(m
078                                    .group(2)));
079            }
080    
081            /**
082             * Compares to version numbers by their major and minor numbers.
083             */
084            public int compareTo(Version other) {
085                    if (major > other.major) {
086                            return 1;
087                    }
088                    if (major < other.major) {
089                            return -1;
090                    }
091    
092                    // major numbers are equal
093                    if (minor > other.minor) {
094                            return 1;
095                    }
096    
097                    if (minor < other.minor) {
098                            return -1;
099                    }
100    
101                    // both are equal
102                    return 0;
103            }
104    
105            /**
106             * Two version are equal if their major and minor version numbers are equal.
107             */
108            @Override
109            public boolean equals(Object other) {
110                    if (other == this) {
111                            return true;
112                    }
113    
114                    if (!(other instanceof Version)) {
115                            return false;
116                    }
117    
118                    return compareTo((Version) other) == 0;
119    
120            }
121    
122            /** Get major version number. */
123            public int getMajor() {
124                    return major;
125            }
126    
127            /** Get minor version number. */
128            public int getMinor() {
129                    return minor;
130            }
131    
132            /**
133             * Hashcode is (major << 7) | minor;
134             */
135            @Override
136            public int hashCode() {
137                    return (major << 7) | minor;
138            }
139    
140            /**
141             * This method is used to check version compatibility in dependency
142             * management.
143             * <p>
144             * Consider the following situation and artefact A (the depender) depends on
145             * another artefact B (the dependee). A claims that it requires B in version
146             * 1.3. B states that it has version 1.5 but is downward compatible to
147             * version 1.1.
148             * <p>
149             * Using this method one can find out if the version provided by B satisfies
150             * A's requirement. It is satisfied iff
151             * 
152             * <pre>
153             * requiredVersion &lt;= currentVersion &amp;&amp; requiredVersion &gt;= compatibleVersion
154             * </pre>
155             * 
156             * where <code>requiredVersion</code> is this instance and the other two
157             * are provided as method parameters.
158             * 
159             * @throws IllegalArgumentException
160             *             if <code>compatibleVersion</code> is greater than
161             *             <code>currentVersion</code>.
162             */
163            public boolean isSatisfied(Version currentVersion, Version compatibleVersion) {
164    
165                    if (compatibleVersion.compareTo(currentVersion) > 0) {
166                            throw new IllegalArgumentException(
167                                            "Compatible version greater than current version.");
168                    }
169    
170                    return this.compareTo(currentVersion) <= 0
171                                    && this.compareTo(compatibleVersion) >= 0;
172            }
173    
174            /**
175             * String representation: major.minor
176             */
177            @Override
178            public String toString() {
179                    return major + "." + minor;
180            }
181    
182    }