001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.plugin;
016    
017    import com.liferay.portal.kernel.util.CharPool;
018    import com.liferay.portal.kernel.util.GetterUtil;
019    import com.liferay.portal.kernel.util.StringBundler;
020    import com.liferay.portal.kernel.util.StringPool;
021    import com.liferay.portal.kernel.util.StringUtil;
022    import com.liferay.portal.kernel.util.Validator;
023    
024    import java.io.Serializable;
025    
026    import java.util.Map;
027    import java.util.StringTokenizer;
028    import java.util.concurrent.ConcurrentHashMap;
029    
030    /**
031     * @author Jorge Ferrer
032     */
033    public class Version implements Comparable<Version>, Serializable {
034    
035            public static final String SNAPSHOT = "SNAPSHOT";
036    
037            public static final String UNKNOWN = "unknown";
038    
039            public static Version getInstance(String version) {
040                    Version versionObj = _versions.get(version);
041    
042                    if (versionObj == null) {
043                            versionObj = new Version(version);
044    
045                            _versions.put(version, versionObj);
046                    }
047    
048                    return versionObj;
049            }
050    
051            public static Version incrementBugFix(Version version) {
052                    String bugFix = version.getBugFix();
053    
054                    int bugFixInt = GetterUtil.getInteger(bugFix);
055    
056                    if (bugFixInt > 0) {
057                            bugFix = String.valueOf(bugFixInt + 1);
058                    }
059    
060                    return getInstance(
061                            _toString(
062                                    version.getMajor(), version.getMinor(), bugFix,
063                                    version.getBuildNumber(), version.getQualifier()));
064            }
065    
066            public static Version incrementBuildNumber(Version version) {
067                    String buildNumber = version.getBuildNumber();
068    
069                    int buildNumberInt = GetterUtil.getInteger(buildNumber);
070    
071                    if (buildNumberInt > 0) {
072                            buildNumber = String.valueOf(buildNumberInt + 1);
073                    }
074    
075                    return getInstance(
076                            _toString(
077                                    version.getMajor(), version.getMinor(), version.getBugFix(),
078                                    buildNumber, version.getQualifier()));
079            }
080    
081            public static Version incrementMajor(Version version) {
082                    String major = version.getMajor();
083    
084                    int majorInt = GetterUtil.getInteger(major);
085    
086                    if (majorInt > 0) {
087                            major = String.valueOf(majorInt + 1);
088                    }
089    
090                    return getInstance(
091                            _toString(
092                                    major, version.getMinor(), version.getBugFix(),
093                                    version.getBuildNumber(), version.getQualifier()));
094            }
095    
096            public static Version incrementMinor(Version version) {
097                    String minor = version.getMinor();
098    
099                    int minorInt = GetterUtil.getInteger(minor);
100    
101                    if (minorInt > 0) {
102                            minor = String.valueOf(minorInt + 1);
103                    }
104    
105                    return getInstance(
106                            _toString(
107                                    version.getMajor(), minor, version.getBugFix(),
108                                    version.getBuildNumber(), version.getQualifier()));
109            }
110    
111            @Override
112            public int compareTo(Version version) {
113                    if (version == null) {
114                            return 1;
115                    }
116    
117                    // Unknown is always considered a lower version
118    
119                    if (version.toString().equals(UNKNOWN)) {
120                            return 1;
121                    }
122    
123                    if (toString().equals(UNKNOWN)) {
124                            return -1;
125                    }
126    
127                    int result = _compareAsIntegers(getMajor(), version.getMajor());
128    
129                    if (result != 0) {
130                            return result;
131                    }
132    
133                    result = _compareAsIntegers(getMinor(), version.getMinor());
134    
135                    if (result != 0) {
136                            return result;
137                    }
138    
139                    result = _compareAsIntegers(getBugFix(), version.getBugFix());
140    
141                    if (result != 0) {
142                            return result;
143                    }
144    
145                    result = _compareAsIntegers(getBuildNumber(), version.getBuildNumber());
146    
147                    if (result != 0) {
148                            return result;
149                    }
150    
151                    return _compareAsQualifiers(getQualifier(), version.getQualifier());
152            }
153    
154            @Override
155            public boolean equals(Object obj) {
156                    if (this == obj) {
157                            return true;
158                    }
159    
160                    if (!(obj instanceof Version)) {
161                            return false;
162                    }
163    
164                    Version version = (Version)obj;
165    
166                    String versionString1 = toString();
167                    String versionString2 = version.toString();
168    
169                    if (versionString1.equals(UNKNOWN) || versionString2.equals(UNKNOWN)) {
170                            return false;
171                    }
172    
173                    return versionString1.equals(versionString2);
174            }
175    
176            public String getBugFix() {
177                    if (_bugFix == null) {
178                            return "0";
179                    }
180    
181                    return _bugFix;
182            }
183    
184            public String getBuildNumber() {
185                    return _buildNumber;
186            }
187    
188            public String getMajor() {
189                    if (_major == null) {
190                            return "0";
191                    }
192    
193                    return _major;
194            }
195    
196            public String getMinor() {
197                    if (_minor == null) {
198                            return "0";
199                    }
200    
201                    return _minor;
202            }
203    
204            public String getQualifier() {
205                    if (_qualifier == null) {
206                            return StringPool.BLANK;
207                    }
208    
209                    return _qualifier;
210            }
211    
212            @Override
213            public int hashCode() {
214                    return toString().hashCode();
215            }
216    
217            public boolean includes(Version version) {
218                    if (equals(version)) {
219                            return true;
220                    }
221    
222                    if (getMajor().equals(StringPool.STAR)) {
223                            return true;
224                    }
225    
226                    if (getMajor().equals(version.getMajor())) {
227                            if (getMinor().equals(StringPool.STAR)) {
228                                    return true;
229                            }
230    
231                            if (getMinor().equals(version.getMinor())) {
232                                    if (getBugFix().equals(StringPool.STAR)) {
233                                            return true;
234                                    }
235    
236                                    if (getBugFix().equals(version.getBugFix())) {
237                                            if (getBuildNumber().equals(StringPool.STAR) ||
238                                                    getBuildNumber().equals(version.getBuildNumber())) {
239    
240                                                    return true;
241                                            }
242                                            else if (_contains(
243                                                                    getBuildNumber(), version.getBuildNumber())) {
244    
245                                                    return true;
246                                            }
247                                    }
248                                    else if (_contains(getBugFix(), version.getBugFix())) {
249                                            return true;
250                                    }
251                            }
252                            else if (_contains(getMinor(), version.getMinor())) {
253                                    return true;
254                            }
255                    }
256                    else if (_contains(getMajor(), version.getMajor())) {
257                            return true;
258                    }
259    
260                    return false;
261            }
262    
263            public boolean isLaterVersionThan(String version) {
264                    if (compareTo(getInstance(version)) > 0) {
265                            return true;
266                    }
267                    else {
268                            return false;
269                    }
270            }
271    
272            public boolean isPreviousVersionThan(String version) {
273                    if (compareTo(getInstance(version)) < 0) {
274                            return true;
275                    }
276                    else {
277                            return false;
278                    }
279            }
280    
281            public boolean isSameVersionAs(String version) {
282                    if (compareTo(getInstance(version)) == 0) {
283                            return true;
284                    }
285                    else {
286                            return false;
287                    }
288            }
289    
290            @Override
291            public String toString() {
292                    return _toString(_major, _minor, _bugFix, _buildNumber, _qualifier);
293            }
294    
295            protected Version(String version) {
296                    int index = version.indexOf(CharPool.DASH);
297    
298                    if (index != -1) {
299                            _qualifier = version.substring(index + 1);
300    
301                            version = version.substring(0, index);
302                    }
303    
304                    StringTokenizer st = new StringTokenizer(version, _SEPARATOR);
305    
306                    _major = st.nextToken();
307    
308                    if (st.hasMoreTokens()) {
309                            _minor = st.nextToken();
310                    }
311    
312                    if (st.hasMoreTokens()) {
313                            _bugFix = st.nextToken();
314                    }
315    
316                    if (st.hasMoreTokens()) {
317                            _buildNumber = st.nextToken();
318                    }
319                    else {
320                            _buildNumber = null;
321                    }
322            }
323    
324            private static boolean _contains(
325                    String containerString, String numberString) {
326    
327                    if (containerString.endsWith(StringPool.PLUS)) {
328                            String containerNumberString = containerString.substring(
329                                    0, containerString.length() - 1);
330    
331                            try {
332                                    int containerNumber = GetterUtil.getInteger(
333                                            containerNumberString);
334                                    int number = GetterUtil.getInteger(numberString);
335    
336                                    return containerNumber <= number;
337                            }
338                            catch (NumberFormatException nfe) {
339                                    return false;
340                            }
341                    }
342    
343                    return false;
344            }
345    
346            private static String _toString(
347                    String major, String minor, String bugFix, String buildNumber,
348                    String qualifier) {
349    
350                    StringBundler sb = new StringBundler(7);
351    
352                    sb.append(major);
353    
354                    if (Validator.isNotNull(minor)) {
355                            sb.append(_SEPARATOR);
356                            sb.append(minor);
357    
358                            if (Validator.isNotNull(bugFix)) {
359                                    sb.append(_SEPARATOR);
360                                    sb.append(bugFix);
361    
362                                    if (Validator.isNotNull(buildNumber)) {
363                                            sb.append(_SEPARATOR);
364                                            sb.append(buildNumber);
365                                    }
366                            }
367                    }
368    
369                    if (Validator.isNotNull(qualifier)) {
370                            sb.append(CharPool.DASH);
371                            sb.append(qualifier);
372                    }
373    
374                    return sb.toString();
375            }
376    
377            private int _compareAsIntegers(String first, String second) {
378                    int firstInteger = GetterUtil.getInteger(first);
379                    int secondInteger = GetterUtil.getInteger(second);
380    
381                    if (firstInteger < secondInteger) {
382                            return -1;
383                    }
384                    else if (firstInteger == secondInteger) {
385                            return 0;
386                    }
387                    else {
388                            return 1;
389                    }
390            }
391    
392            private int _compareAsQualifiers(String first, String second) {
393                    String firstString = GetterUtil.getString(first);
394                    String secondString = GetterUtil.getString(second);
395    
396                    if (StringUtil.equalsIgnoreCase(firstString, SNAPSHOT) &&
397                            !StringUtil.equalsIgnoreCase(secondString, SNAPSHOT)) {
398    
399                            return -1;
400                    }
401                    else if (!StringUtil.equalsIgnoreCase(firstString, SNAPSHOT) &&
402                                     StringUtil.equalsIgnoreCase(secondString, SNAPSHOT)) {
403    
404                            return 1;
405                    }
406    
407                    return 0;
408            }
409    
410            private static final String _SEPARATOR = StringPool.PERIOD;
411    
412            private static final Map<String, Version> _versions =
413                    new ConcurrentHashMap<>();
414    
415            private String _bugFix;
416            private final String _buildNumber;
417            private String _major;
418            private String _minor;
419            private String _qualifier;
420    
421    }