View Javadoc
1   /*
2    * Copyright (C) 2006-2007 the original author or authors.
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   */
16  
17  package org.codehaus.gmavenplus.model.internal;
18  
19  import java.util.Arrays;
20  
21  
22  /**
23   * Container for Version information in the form of <i>major.minor.revision-tag</i>.
24   *
25   * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
26   * @author Keegan Witt
27   * @since 1.0-beta-1
28   */
29  public class Version implements Comparable<Version> {
30  
31      /**
32       * The version major number.
33       */
34      private int major;
35  
36      /**
37       * The version minor number.
38       */
39      private int minor;
40  
41      /**
42       * The version revision.
43       */
44      private int revision;
45  
46      /**
47       * The version tag.
48       */
49      private String tag;
50  
51      /**
52       * Constructs a new version object with the specified parameters.
53       *
54       * @param newMajor    The version major number
55       * @param newMinor    The version minor number
56       * @param newRevision The version revision number
57       * @param newTag      The version tag string
58       */
59      public Version(final int newMajor, final int newMinor, final int newRevision, final String newTag) {
60          if (newMajor < 0 || newMinor < 0 || newRevision < 0) {
61              // note we don't check the tag since it can be null
62              throw new IllegalArgumentException("Major must be >= 0 and minor >= 0 and revision >= 0.");
63          }
64  
65          major = newMajor;
66          minor = newMinor;
67          revision = newRevision;
68          if (newTag == null || !newTag.isEmpty()) {
69              tag = newTag;
70          } else {
71              tag = null;
72          }
73      }
74  
75      /**
76       * Constructs a new Version object with the specified parameters.
77       *
78       * @param newMajor    The version major number
79       * @param newMinor    The version minor number
80       * @param newRevision The version revision number
81       */
82      public Version(final int newMajor, final int newMinor, final int newRevision) {
83          this(newMajor, newMinor, newRevision, null);
84      }
85  
86      /**
87       * Constructs a new Version object with the specified parameters.
88       *
89       * @param newMajor The version major number
90       * @param newMinor The version minor number
91       */
92      public Version(final int newMajor, final int newMinor) {
93          this(newMajor, newMinor, 0);
94      }
95  
96      /**
97       * Constructs a new Version object with the specified parameters.
98       *
99       * @param newMajor The version major number
100      */
101     public Version(final int newMajor) {
102         this(newMajor, 0);
103     }
104 
105     /**
106      * Parses a new Version object from a string.
107      *
108      * @param version The version string to parse
109      * @return The version parsed from the string
110      */
111     public static Version parseFromString(final String version) {
112         if (version == null || version.isEmpty()) {
113             throw new IllegalArgumentException("Version must not be null or empty.");
114         }
115         String[] split = version.split("[._-]", 4);
116         try {
117             int tagIdx = 3;
118             int major = Integer.parseInt(split[0]);
119             int minor = 0;
120             int revision = 0;
121             StringBuilder tag = new StringBuilder();
122             if (split.length >= 2) {
123                 try {
124                     minor = Integer.parseInt(split[1]);
125                 } catch (NumberFormatException nfe) {
126                     // version string must not have specified a minor version, leave minor as 0 and append to tag instead
127                     tag.append(split[1]);
128                     tagIdx = 1;
129                     tag.append("-");
130                 }
131             }
132             if (split.length >= 3) {
133                 try {
134                     revision = Integer.parseInt(split[2]);
135                 } catch (NumberFormatException nfe) {
136                     // version string must not have specified a revision version, leave revision as 0 and append to tag instead
137                     tag.append(split[2]);
138                     tagIdx = 2;
139                     tag.append("-");
140                 }
141             }
142             if (split.length >= 4) {
143                 for (int i = tagIdx; i < split.length; i++) {
144                     if (i > tagIdx) {
145                         tag.append("-");
146                     }
147                     tag.append(split[i]);
148                 }
149             }
150             return new Version(major, minor, revision, tag.toString());
151         } catch (NumberFormatException e) {
152             throw new IllegalArgumentException("Major, minor, and revision must be integers.", e);
153         }
154     }
155 
156     /**
157      * Returns a hash code for this object.
158      *
159      * @return The hash code for this object
160      * @see java.lang.Object#hashCode()
161      */
162     @Override
163     public final int hashCode() {
164         return Arrays.hashCode(new Object[]{major, minor, revision, tag});
165     }
166 
167     /**
168      * Determines whether the specified object is equal to this object.
169      *
170      * @param obj The object to compare to this object
171      * @return <code>true</code> if the specified object is equal to this object, <code>false</code> otherwise
172      * @see java.lang.Object#equals(java.lang.Object)
173      */
174     @Override
175     public final boolean equals(final Object obj) {
176         if (obj == null) {
177             return false;
178         }
179         if (obj == this) {
180             return true;
181         }
182         if (obj.getClass() != getClass()) {
183             return false;
184         }
185         return compareTo((Version) obj) == 0;
186     }
187 
188     /**
189      * Returns a String representation of this object.
190      *
191      * @return The String representation of this object
192      * @see java.lang.Object#toString()
193      */
194     @Override
195     public final String toString() {
196         StringBuilder buff = new StringBuilder();
197 
198         buff.append(major)
199                 .append(".").append(minor)
200                 .append(".").append(revision);
201         if (tag != null) {
202             buff.append("-").append(tag);
203         }
204 
205         return buff.toString();
206     }
207 
208     /**
209      * Compares two versions objects. Note that if the major, minor, and revision are all the same, tags are compared with
210      * {@link java.lang.String#compareTo(String) String.compareTo()}. Having no tag is considered a newer version than a version with a tag.
211      *
212      * @param version The version to compare this version to
213      * @return <code>0</code> if the version is equal to this version, <code>1</code> if the version is greater than
214      * this version, or <code>-1</code> if the version is lower than this version.
215      */
216     @Override
217     public final int compareTo(final Version version) {
218         return compareTo(version, true);
219     }
220 
221     /**
222      * Compares two versions objects. Note that if the major, minor, and revision are all the same, tags are compared with
223      * {@link java.lang.String#compareTo(String) String.compareTo()}.
224      *
225      * @param version        The version to compare this version to
226      * @param noTagsAreNewer Whether versions with no tag are considered newer than those that have tags
227      * @return <code>0</code> if the version is equal to this version, <code>1</code> if the version is greater than
228      * this version, or <code>-1</code> if the version is lower than this version.
229      */
230     public final int compareTo(final Version version, final boolean noTagsAreNewer) {
231         // "beta" is replaced with " beta" to make sure RCs are considered newer than betas (by moving beta to back of order)
232         int comp = Integer.compare(major, version.major);
233         if (comp == 0) {
234             comp = Integer.compare(minor, version.minor);
235         }
236         if (comp == 0) {
237             comp = Integer.compare(revision, version.revision);
238         }
239         if (comp == 0) {
240             if (tag != null && version.tag != null) {
241                 return tag.replace("beta", " beta").replace("alpha", " alpha")
242                         .compareTo(version.tag.replace("beta", " beta").replace("alpha", " alpha"));
243             } else if (tag == null ^ version.tag == null) {
244                 if (tag == null) {
245                     return noTagsAreNewer ? 1 : -1;
246                 } else {
247                     return noTagsAreNewer ? -1 : 1;
248                 }
249             } else {
250                 return comp;
251             }
252         } else {
253             return comp;
254         }
255     }
256 
257     /**
258      * Gets the version major number.
259      *
260      * @return The major version number
261      */
262     public int getMajor() {
263         return major;
264     }
265 
266     /**
267      * Sets the version major number.
268      *
269      * @param newMajor The major version number to set
270      * @return This object (for fluent invocation)
271      */
272     public Version setMajor(final int newMajor) {
273         major = newMajor;
274         return this;
275     }
276 
277     /**
278      * Gets the version minor number.
279      *
280      * @return The version minor number
281      */
282     public int getMinor() {
283         return minor;
284     }
285 
286     /**
287      * Sets the version minor number.
288      *
289      * @param newMinor The version minor number to set
290      * @return This object (for fluent invocation)
291      */
292     public Version setMinor(final int newMinor) {
293         minor = newMinor;
294         return this;
295     }
296 
297     /**
298      * Gets the version revision number.
299      *
300      * @return The version revision number
301      */
302     public int getRevision() {
303         return revision;
304     }
305 
306     /**
307      * Sets the version revision number.
308      *
309      * @param newRevision The revision number to set
310      * @return This object (for fluent invocation)
311      */
312     public Version setRevision(final int newRevision) {
313         revision = newRevision;
314         return this;
315     }
316 
317     /**
318      * Gets the version tag string.
319      *
320      * @return The version tag string
321      */
322     public String getTag() {
323         return tag;
324     }
325 
326     /**
327      * Sets the version tag string.
328      *
329      * @param newTag The version tag string to set
330      * @return This object (for fluent invocation)
331      */
332     public Version setTag(final String newTag) {
333         tag = newTag;
334         return this;
335     }
336 
337 }