View Javadoc
1   package org.apache.maven.artifact.versioning;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.StringTokenizer;
23  
24  import static org.apache.commons.lang3.math.NumberUtils.isDigits;
25  
26  /**
27   * Default implementation of artifact versioning.
28   *
29   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
30   */
31  public class DefaultArtifactVersion
32      implements ArtifactVersion
33  {
34      private Integer majorVersion;
35  
36      private Integer minorVersion;
37  
38      private Integer incrementalVersion;
39  
40      private Integer buildNumber;
41  
42      private String qualifier;
43  
44      private ComparableVersion comparable;
45  
46      public DefaultArtifactVersion( String version )
47      {
48          parseVersion( version );
49      }
50  
51      @Override
52      public int hashCode()
53      {
54          return 11 + comparable.hashCode();
55      }
56  
57      @Override
58      public boolean equals( Object other )
59      {
60          if ( this == other )
61          {
62              return true;
63          }
64  
65          if ( !( other instanceof ArtifactVersion ) )
66          {
67              return false;
68          }
69  
70          return compareTo( (ArtifactVersion) other ) == 0;
71      }
72  
73      public int compareTo( ArtifactVersion otherVersion )
74      {
75          if ( otherVersion instanceof DefaultArtifactVersion )
76          {
77              return this.comparable.compareTo( ( (DefaultArtifactVersion) otherVersion ).comparable );
78          }
79          else
80          {
81              return compareTo( new DefaultArtifactVersion( otherVersion.toString() ) );
82          }
83      }
84  
85      public int getMajorVersion()
86      {
87          return majorVersion != null ? majorVersion : 0;
88      }
89  
90      public int getMinorVersion()
91      {
92          return minorVersion != null ? minorVersion : 0;
93      }
94  
95      public int getIncrementalVersion()
96      {
97          return incrementalVersion != null ? incrementalVersion : 0;
98      }
99  
100     public int getBuildNumber()
101     {
102         return buildNumber != null ? buildNumber : 0;
103     }
104 
105     public String getQualifier()
106     {
107         return qualifier;
108     }
109 
110     public final void parseVersion( String version )
111     {
112         comparable = new ComparableVersion( version );
113 
114         int index = version.indexOf( '-' );
115 
116         String part1;
117         String part2 = null;
118 
119         if ( index < 0 )
120         {
121             part1 = version;
122         }
123         else
124         {
125             part1 = version.substring( 0, index );
126             part2 = version.substring( index + 1 );
127         }
128 
129         if ( part2 != null )
130         {
131             if ( part2.length() == 1  || !part2.startsWith( "0" ) )
132             {
133                 buildNumber = tryParseInt( part2 );
134                 if ( buildNumber == null )
135                 {
136                     qualifier = part2;
137                 }
138             }
139             else
140             {
141                 qualifier = part2;
142             }
143         }
144 
145         if ( ( !part1.contains( "." ) ) && !part1.startsWith( "0" ) )
146         {
147             majorVersion = tryParseInt( part1 );
148             if ( majorVersion == null )
149             {
150                 // qualifier is the whole version, including "-"
151                 qualifier = version;
152                 buildNumber = null;
153             }
154         }
155         else
156         {
157             boolean fallback = false;
158 
159             StringTokenizer tok = new StringTokenizer( part1, "." );
160             if ( tok.hasMoreTokens() )
161             {
162                 majorVersion = getNextIntegerToken( tok );
163                 if ( majorVersion == null )
164                 {
165                     fallback = true;
166                 }
167             }
168             else
169             {
170                 fallback = true;
171             }
172             if ( tok.hasMoreTokens() )
173             {
174                 minorVersion = getNextIntegerToken( tok );
175                 if ( minorVersion == null )
176                 {
177                     fallback = true;
178                 }
179             }
180             if ( tok.hasMoreTokens() )
181             {
182                 incrementalVersion = getNextIntegerToken( tok );
183                 if ( incrementalVersion == null )
184                 {
185                     fallback = true;
186                 }
187             }
188             if ( tok.hasMoreTokens() )
189             {
190                 qualifier = tok.nextToken();
191                 fallback = isDigits( qualifier );
192             }
193 
194             // string tokenizer won't detect these and ignores them
195             if ( part1.contains( ".." ) || part1.startsWith( "." ) || part1.endsWith( "." ) )
196             {
197                 fallback = true;
198             }
199 
200             if ( fallback )
201             {
202                 // qualifier is the whole version, including "-"
203                 qualifier = version;
204                 majorVersion = null;
205                 minorVersion = null;
206                 incrementalVersion = null;
207                 buildNumber = null;
208             }
209         }
210     }
211 
212     private static Integer getNextIntegerToken( StringTokenizer tok )
213     {
214         String s = tok.nextToken();
215         if ( ( s.length() > 1 ) && s.startsWith( "0" ) )
216         {
217             return null;
218         }
219         return tryParseInt( s );
220     }
221 
222     private static Integer tryParseInt( String s )
223     {
224         // for performance, check digits instead of relying later on catching NumberFormatException
225         if ( !isDigits( s ) )
226         {
227             return null;
228         }
229 
230         try
231         {
232             long longValue = Long.parseLong( s );
233             if ( longValue > Integer.MAX_VALUE )
234             {
235                 return null;
236             }
237             return (int) longValue;
238         }
239         catch ( NumberFormatException e )
240         {
241             // should never happen since checked isDigits(s) before 
242             return null;
243         }
244     }
245 
246     @Override
247     public String toString()
248     {
249         return comparable.toString();
250     }
251 }