001/*
002 * Copyright 2016 The AppAuth for Android Authors. All Rights Reserved.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the
010 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
011 * express or implied. See the License for the specific language governing permissions and
012 * limitations under the License.
013 */
014
015package net.openid.appauth.browser;
016
017import androidx.annotation.NonNull;
018import androidx.annotation.Nullable;
019
020/**
021 * A browser filter which matches when a browser falls into a version range. Versions are
022 * expected to match the semantics of {@link DelimitedVersion}.
023 */
024public class VersionRange {
025
026    /**
027     * A version range that matches any delimited version.
028     */
029    public static final VersionRange ANY_VERSION = new VersionRange(null, null);
030
031    private DelimitedVersion mLowerBound;
032    private DelimitedVersion mUpperBound;
033
034    /**
035     * Creates a version range that will match any version at or above the specified version,
036     * which will be parsed as a {@link DelimitedVersion}.
037     */
038    public static VersionRange atLeast(String version) {
039        return atLeast(DelimitedVersion.parse(version));
040    }
041
042    /**
043     * Creates a version range that will match any version at or above the specified version.
044     */
045    public static VersionRange atLeast(DelimitedVersion version) {
046        return new VersionRange(version, null);
047    }
048
049    /**
050     * Creates a version range that will match any version at or below the specified version,
051     * which will be parsed as a {@link DelimitedVersion}.
052     */
053    public static VersionRange atMost(String version) {
054        return atMost(DelimitedVersion.parse(version));
055    }
056
057    /**
058     * Creates a version range that will match any version at or below the specified version.
059     */
060    public static VersionRange atMost(DelimitedVersion version) {
061        return new VersionRange(null, version);
062    }
063
064    /**
065     * Creates a version range that will match any version equal to or between the specified
066     * versions, which will be parsed as {@link DelimitedVersion} instances.
067     */
068    public static VersionRange between(String lowerBound, String upperBound) {
069        return new VersionRange(
070                DelimitedVersion.parse(lowerBound),
071                DelimitedVersion.parse(upperBound));
072    }
073
074    /**
075     * Creates a version range with the specified bounds. A null bound is treated as "no bound"
076     * on that end.
077     */
078    public VersionRange(
079            @Nullable DelimitedVersion lowerBound,
080            @Nullable DelimitedVersion upperBound) {
081        mLowerBound = lowerBound;
082        mUpperBound = upperBound;
083    }
084
085    /**
086     * Determines whether the specified version (parsed as an {@link DelimitedVersion} falls within
087     * the version range.
088     */
089    public boolean matches(@NonNull String version) {
090        return matches(DelimitedVersion.parse(version));
091    }
092
093    /**
094     * Determines whether the specified version falls within the version range.
095     */
096    public boolean matches(@NonNull DelimitedVersion version) {
097        if (mLowerBound != null && mLowerBound.compareTo(version) > 0) {
098            return false;
099        }
100
101        if (mUpperBound != null && mUpperBound.compareTo(version) < 0) {
102            return false;
103        }
104
105        return true;
106    }
107
108    @Override
109    public String toString() {
110        if (mLowerBound == null) {
111            if (mUpperBound == null) {
112                return "any version";
113            }
114
115            return mUpperBound.toString() + " or lower";
116        }
117
118        if (mUpperBound != null) {
119            return "between " + mLowerBound + " and " + mUpperBound;
120        }
121
122        return mLowerBound.toString() + " or higher";
123    }
124}