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