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