001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.eclipse.aether.util.version;
020
021import java.util.ArrayList;
022import java.util.Collection;
023
024import org.eclipse.aether.version.InvalidVersionSpecificationException;
025import org.eclipse.aether.version.VersionRange;
026import org.eclipse.aether.version.VersionScheme;
027
028import static java.util.Objects.requireNonNull;
029
030/**
031 * A version scheme support class. A new implementation should extend this class and would receive full support for
032 * ranges and constraints. The new implementation should implement {@link org.eclipse.aether.version.Version} and
033 * the one missing method in this class, the {@link #parseVersion(String)}.
034 *
035 * @since 2.0.0
036 */
037public abstract class VersionSchemeSupport implements VersionScheme {
038    @Override
039    public GenericVersionRange parseVersionRange(final String range) throws InvalidVersionSpecificationException {
040        return new GenericVersionRange(this, range);
041    }
042
043    @Override
044    public GenericVersionConstraint parseVersionConstraint(final String constraint)
045            throws InvalidVersionSpecificationException {
046        String process = requireNonNull(constraint, "constraint cannot be null");
047
048        Collection<VersionRange> ranges = new ArrayList<>();
049
050        while (process.startsWith("[") || process.startsWith("(")) {
051            int index1 = process.indexOf(')');
052            int index2 = process.indexOf(']');
053
054            int index = index2;
055            if (index2 < 0 || (index1 >= 0 && index1 < index2)) {
056                index = index1;
057            }
058
059            if (index < 0) {
060                throw new InvalidVersionSpecificationException(constraint, "Unbounded version range " + constraint);
061            }
062
063            VersionRange range = parseVersionRange(process.substring(0, index + 1));
064            ranges.add(range);
065
066            process = process.substring(index + 1).trim();
067
068            if (process.startsWith(",")) {
069                process = process.substring(1).trim();
070            }
071        }
072
073        if (!process.isEmpty() && !ranges.isEmpty()) {
074            throw new InvalidVersionSpecificationException(
075                    constraint, "Invalid version range " + constraint + ", expected [ or ( but got " + process);
076        }
077
078        GenericVersionConstraint result;
079        if (ranges.isEmpty()) {
080            result = new GenericVersionConstraint(parseVersion(constraint));
081        } else {
082            result = new GenericVersionConstraint(UnionVersionRange.from(ranges));
083        }
084
085        return result;
086    }
087}