001/*
002 * (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Julien Carsique
016 *
017 */
018
019package org.nuxeo.common.utils;
020
021import java.util.ArrayList;
022import java.util.List;
023import java.util.regex.Pattern;
024
025/**
026 * Compare versions of files as they are usually set. Maven classifiers are not managed: a classifier will be considered
027 * as being part of the version. Maven "SNAPSHOT" keyword is taken in account. Rule is: x-SNAPSHOT < x <
028 * x-AnythingButSNAPSHOT < x.y-SNAPSHOT < x.y
029 *
030 * @since 5.5
031 */
032public class FileVersion implements Comparable<FileVersion> {
033
034    protected static final String SNAPSHOT = "-SNAPSHOT";
035
036    protected String version;
037
038    protected boolean snapshot;
039
040    protected boolean specialQualifier;
041
042    protected Integer[] splitVersion;
043
044    protected String qualifier = "";
045
046    private String separator = "";
047
048    private String tmpVersion;
049
050    private static final Pattern SPECIAL_QUALIFIER = Pattern.compile("^-(((RC)|(rc)|(alpha)|(ALPHA)|(beta)|(BETA)\\d+)|([a-zA-Z][0-9]{8})).*$");
051
052    public String getQualifier() {
053        return qualifier;
054    }
055
056    public Integer[] getSplitVersion() {
057        return splitVersion;
058    }
059
060    public FileVersion(String value) {
061        this.version = value;
062        this.snapshot = value.endsWith(SNAPSHOT);
063        split(getVersionWithoutSnapshot());
064        this.specialQualifier = SPECIAL_QUALIFIER.matcher(qualifier).matches();
065    }
066
067    public void split(String value) {
068        if (value.startsWith("r")) {
069            // special case for caja-r1234 versions
070            value = value.substring(1);
071        }
072        List<Integer> versions = new ArrayList<Integer>();
073        this.tmpVersion = value;
074        do {
075            if (".".equals(separator)) {
076                try {
077                    versions.add(Integer.valueOf(tmpVersion));
078                    break;
079                } catch (NumberFormatException e) {
080                }
081            }
082            if (splitWith(".", versions)) {
083                continue;
084            }
085            if (splitWith("-", versions)) {
086                continue;
087            }
088            if (splitWith("_", versions)) {
089                continue;
090            }
091            qualifier = separator + tmpVersion;
092            break;
093        } while (true);
094        splitVersion = versions.toArray(new Integer[0]);
095    }
096
097    private boolean splitWith(String token, List<Integer> versions) {
098        try {
099            int index = tmpVersion.indexOf(token);
100            if (index > 0) {
101                versions.add(Integer.valueOf(tmpVersion.substring(0, index)));
102                separator = tmpVersion.substring(index, index + 1);
103                tmpVersion = tmpVersion.substring(index + 1);
104                return true;
105            } else {
106                // treat versions containing only major versions: "1-q", "2"
107                // etc.
108                if (versions.isEmpty()) {
109                    versions.add(Integer.valueOf(tmpVersion));
110                    return false;
111                }
112            }
113        } catch (NumberFormatException e) {
114        }
115        return false;
116    }
117
118    @Override
119    public int compareTo(FileVersion o) {
120        if (snapshot && getVersionWithoutSnapshot().equals(o.getVersion()) || specialQualifier
121                && getVersionWithoutQualifier().equals(o.getVersion())) {
122            return -1;
123        } else if (o.isSnapshot() && version.equals(o.getVersionWithoutSnapshot()) || o.hasSpecialQualifier()
124                && version.equals(o.getVersionWithoutQualifier())) {
125            return 1;
126        }
127
128        int index = 0, number, oNumber, result;
129        do {
130            if (splitVersion.length > index) {
131                number = splitVersion[index];
132            } else {
133                number = 0;
134            }
135            if (o.getSplitVersion().length > index) {
136                oNumber = o.getSplitVersion()[index];
137            } else {
138                oNumber = 0;
139            }
140            result = number - oNumber;
141            index++;
142        } while (result == 0 && (splitVersion.length > index || o.getSplitVersion().length > index));
143        if (result == 0) {
144            result = qualifier.compareTo(o.getQualifier());
145        }
146        return result;
147    }
148
149    @Override
150    public boolean equals(Object o) {
151        return (this == o || o != null && (o instanceof FileVersion) && compareTo((FileVersion) o) == 0);
152    }
153
154    public String getVersion() {
155        return version;
156    }
157
158    public String getVersionWithoutSnapshot() {
159        if (snapshot) {
160            return version.substring(0, version.lastIndexOf(SNAPSHOT));
161        }
162        return version;
163    }
164
165    public boolean greaterThan(FileVersion other) {
166        return compareTo(other) > 0;
167    }
168
169    public boolean lessThan(FileVersion other) {
170        return compareTo(other) < 0;
171    }
172
173    public boolean isSnapshot() {
174        return snapshot;
175    }
176
177    /**
178     * @since 5.6
179     */
180    public boolean hasSpecialQualifier() {
181        return specialQualifier;
182    }
183
184    /**
185     * @since 5.6
186     */
187    public String getVersionWithoutQualifier() {
188        return version.substring(0, version.lastIndexOf(qualifier));
189    }
190
191    @Override
192    public String toString() {
193        return version;
194    }
195
196}