001    /*
002     * Copyright 2001-2005 The Apache Software Foundation.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.apache.geronimo.kernel.repository;
017    
018    import java.util.StringTokenizer;
019    import java.io.Serializable;
020    
021    /**
022     * Default implementation of artifact versioning.
023     *
024     * @author <a href="mailto:brett@apache.org">Brett Porter</a>
025     * @version $Id: Version.java 410741 2006-06-01 04:35:48Z jsisson $
026     */
027    // This code was lifted from Apache Maven
028    public class Version implements Comparable, Serializable {
029        // Geronimo adds Serial UID because we serialize versions into config.ser
030        private static final long serialVersionUID = 7941704456058067109L;
031    
032        private Integer majorVersion;
033    
034        private Integer minorVersion;
035    
036        private Integer incrementalVersion;
037    
038        private Integer buildNumber;
039    
040        private String qualifier;
041    
042        public Version(String version) {
043            parseVersion(version);
044        }
045    
046        public int compareTo(Object o) {
047            Version otherVersion = (Version) o;
048    
049            int result = compareIntegers(majorVersion, otherVersion.majorVersion);
050            if (result == 0) {
051                result = compareIntegers(minorVersion, otherVersion.minorVersion);
052            }
053            if (result == 0) {
054                result = compareIntegers(incrementalVersion, otherVersion.incrementalVersion);
055            }
056            if (result == 0) {
057                if (buildNumber != null || otherVersion.buildNumber != null) {
058                    result = compareIntegers(buildNumber, otherVersion.buildNumber);
059                } else if (qualifier != null) {
060                    if (otherVersion.qualifier != null) {
061                        if (qualifier.length() > otherVersion.qualifier.length() &&
062                                qualifier.startsWith(otherVersion.qualifier)) {
063                            // here, the longer one that otherwise match is considered older
064                            result = -1;
065                        } else if (qualifier.length() < otherVersion.qualifier.length() &&
066                                otherVersion.qualifier.startsWith(qualifier)) {
067                            // here, the longer one that otherwise match is considered older
068                            result = 1;
069                        } else {
070                            result = qualifier.compareTo(otherVersion.qualifier);
071                        }
072                    } else {
073                        // otherVersion has no qualifier but we do - that's newer
074                        result = -1;
075                    }
076                } else if (otherVersion.qualifier != null) {
077                    // otherVersion has a qualifier but we don't, we're newer
078                    result = 1;
079                }
080            }
081            return result;
082        }
083    
084        private int compareIntegers(Integer i1, Integer i2) {
085            // treat null as 0 in comparison
086            if (i1 == null ? i2 == null : i1.equals(i2)) {
087                return 0;
088            } else if (i1 == null) {
089                return -i2.intValue();
090            } else if (i2 == null) {
091                return i1.intValue();
092            } else {
093                return i1.intValue() - i2.intValue();
094            }
095        }
096    
097        public int getMajorVersion() {
098            return majorVersion != null ? majorVersion.intValue() : 0;
099        }
100    
101        public int getMinorVersion() {
102            return minorVersion != null ? minorVersion.intValue() : 0;
103        }
104    
105        public int getIncrementalVersion() {
106            return incrementalVersion != null ? incrementalVersion.intValue() : 0;
107        }
108    
109        public int getBuildNumber() {
110            return buildNumber != null ? buildNumber.intValue() : 0;
111        }
112    
113        public String getQualifier() {
114            return qualifier;
115        }
116    
117        public final void parseVersion(String version) {
118            int index = version.indexOf("-");
119    
120            String part1;
121            String part2 = null;
122    
123            if (index < 0) {
124                part1 = version;
125            } else {
126                part1 = version.substring(0, index);
127                part2 = version.substring(index + 1);
128            }
129    
130            if (part2 != null) {
131                try {
132                    if (part2.length() == 1 || !part2.startsWith("0")) {
133                        buildNumber = Integer.valueOf(part2);
134                    } else {
135                        qualifier = part2;
136                    }
137                }
138                catch (NumberFormatException e) {
139                    qualifier = part2;
140                }
141            }
142    
143            if (part1.indexOf(".") < 0 && !part1.startsWith("0")) {
144                try {
145                    majorVersion = Integer.valueOf(part1);
146                }
147                catch (NumberFormatException e) {
148                    // qualifier is the whole version, including "-"
149                    qualifier = version;
150                    buildNumber = null;
151                }
152            } else {
153                boolean fallback = false;
154                StringTokenizer tok = new StringTokenizer(part1, ".");
155                try {
156                    majorVersion = getNextIntegerToken(tok);
157                    if (tok.hasMoreTokens()) {
158                        minorVersion = getNextIntegerToken(tok);
159                    }
160                    if (tok.hasMoreTokens()) {
161                        incrementalVersion = getNextIntegerToken(tok);
162                    }
163                    if (tok.hasMoreTokens()) {
164                        fallback = true;
165                    }
166                }
167                catch (NumberFormatException e) {
168                    fallback = true;
169                }
170    
171                if (fallback) {
172                    // qualifier is the whole version, including "-"
173                    qualifier = version;
174                    majorVersion = null;
175                    minorVersion = null;
176                    incrementalVersion = null;
177                }
178            }
179        }
180    
181        private static Integer getNextIntegerToken(StringTokenizer tok) {
182            String s = tok.nextToken();
183            if (s.length() > 1 && s.startsWith("0")) {
184                throw new NumberFormatException("Number part has a leading 0: '" + s + "'");
185            }
186            return Integer.valueOf(s);
187        }
188    
189        public String toString() {
190            StringBuffer buf = new StringBuffer();
191            if (majorVersion != null) {
192                buf.append(majorVersion);
193            }
194            if (minorVersion != null) {
195                buf.append(".");
196                buf.append(minorVersion);
197            }
198            if (incrementalVersion != null) {
199                buf.append(".");
200                buf.append(incrementalVersion);
201            }
202            if (buildNumber != null) {
203                buf.append("-");
204                buf.append(buildNumber);
205            } else if (qualifier != null) {
206                if (buf.length() > 0) {
207                    buf.append("-");
208                }
209                buf.append(qualifier);
210            }
211            return buf.toString();
212        }
213    
214        public boolean equals(Object other) {
215            if (this == other) {
216                return true;
217            }
218            if (other == null || this.getClass() != other.getClass()) {
219                return false;
220            }
221            Version v = (Version) other;
222            if (majorVersion == null? v.majorVersion != null: !majorVersion.equals(v.majorVersion)) {
223                return false;
224            }
225            if (minorVersion == null? v.minorVersion != null: !minorVersion.equals(v.minorVersion)) {
226                return false;
227            }
228            if (incrementalVersion == null? v.incrementalVersion != null: !incrementalVersion.equals(v.incrementalVersion)) {
229                return false;
230            }
231            if (buildNumber == null? v.buildNumber != null: !buildNumber.equals(v.buildNumber)) {
232                return false;
233            }
234            return qualifier == null ? v.qualifier == null : qualifier.equals(v.qualifier);
235        }
236    
237        public int hashCode() {
238            int hashCode = 0;
239            if (majorVersion != null) {
240                hashCode = majorVersion.intValue();
241            }
242            if (minorVersion != null) {
243                hashCode = 37 * hashCode + minorVersion.intValue();
244            }
245            if (incrementalVersion != null) {
246                hashCode = 37 * hashCode + incrementalVersion.intValue();
247            }
248            if (buildNumber != null) {
249                hashCode = 37 * hashCode + buildNumber.intValue();
250            }
251            if (qualifier != null) {
252                hashCode = 37 * hashCode + qualifier.hashCode();
253            }
254            return hashCode;
255        }
256    }