All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.metaeffekt.mirror.contents.eol.EolCycle Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.metaeffekt.mirror.contents.eol;

import com.metaeffekt.artifact.analysis.utils.StringUtils;
import com.metaeffekt.artifact.analysis.utils.TimeUtils;
import com.metaeffekt.artifact.analysis.version.Version;
import com.metaeffekt.artifact.analysis.vulnerability.enrichment.VersionComparator;
import com.metaeffekt.mirror.contents.eol.state.*;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.json.JSONObject;

import java.util.Comparator;
import java.util.Date;
import java.util.Objects;

import static org.apache.commons.lang3.ObjectUtils.firstNonNull;

/**
 * Represents an end-of-life (EOL) cycle for a product.
 * 

* This class stores information about a product's EOL cycle, including its release date, EOL date, latest version, * LTS (Long-Term Support) status, and other related information. */ public class EolCycle implements Comparable { private String product; private final String cycle; private final String releaseDate; private final String latest; private final String latestReleaseDate; private final String link; /** *

string<date> or boolean

*
    *
  • if boolean: true means it has reached the end of life state, without a specific date and false means that the end * of life state has not been set yet
  • *
  • if date: the release reaches the end of life state on this date, which can be a date in the past or in the future
  • *
*/ private final String eol; /** *

string<date> or boolean

*

Similar to eol, but for when/if long term support is available for the version.

*
    *
  • if boolean: true means it has long term support and false means that lts is most likely never going to be * available for this version
  • *
  • if date: the cycle enters long term support on this date, which can be a date in the past or in the future
  • *
*/ private final String lts; /** *

string<date> or boolean

*

Similar to eol, but for when/if the version is discontinued.

*
    *
  • if boolean: true means it has been discontinued and false means that the version is not discontinued
  • *
  • if date: the cycle is discontinued on this date, which can be a date in the past or in the future
  • *
*/ private final String discontinued; /** *

string<date> or boolean or null

*

Similar to eol, but for when/if the version still provides support by the vendor.

*
    *
  • if boolean: true means it is still supported and false means that the version is not supported anymore
  • *
  • if date: the cycle is still supported up till this date, which can be a date in the past or in the future
  • *
  • if null: inverted eol field, meaning that if the product is not end of life, it is still supported (see rabbitmq * below for example)
  • *
*

     * {
     *   "product": "rabbitmq",
     *   "eol": "2023-12-31",
     *   "extendedSupport": "2024-07-31",
     * }
     * 
*

Note that the extended support may differ from the support date, and that there is no support date specified. This means * that the product ends support on the 2023-12-31 and that extended support is available until 2024-07-31.

*/ private final String support; /** *

string<date> or boolean or null

*

Similar to support, but for when/if the version still provides extended support by the vendor.

*
    *
  • if boolean: true means it is still supported and false means that the version is not supported anymore
  • *
  • if date: the cycle is still supported up till this date, which can be a date in the past or in the future
  • *
  • if null: see below
  • *
*

https://endoflife.date/almalinux:

*
{
     *   "product": "almalinux",
     *   "cycle": "9",
     *   "eol": "2032-05-31",
     *   "support": "2027-05-31"
     * }
     * 
*

Meaning that security support ends on 31 May 2032 (eol), the same date as the end of life for AlmaLinux 9. The end of * the regular support period is 31 May 2027 (support).

*

There is another case, however:

*

https://endoflife.date/samsung-mobile

*
{
     *   "product": "samsung-mobile",
     *   "cycle": "Galaxy A8s",
     *   "eol": "false",
     *   "support": "false"
     * }
     * 
*

Which the EOL Date page interprets as Yes. This is because the eol and support fields are false, which means * that the product is not supported by regular support, but the EOL has not been reached yet, so the extended support is * still available.

*

On the same product, there is another example where the eol field is set to a date and the support is false. In this * case, too, the extended support uses the eol date:

*
{
     *   "product": "samsung-mobile",
     *   "cycle": "Galaxy A2 Core",
     *   "eol": "2021-10-01",
     *   "support": "false"
     * }
     * 
*/ private final String extendedSupport; /** *

string<date>

*

The date on which technical guidance ends for the product. This is not the same as the end of life date, but the date * on which the vendor stops providing technical guidance for the product.

*/ private final String technicalGuidance; /** *

As of writing this document, the supportedPhpVersions field is only used by the magento and laravel products. It * is a csv list of versions, with each version entry either being a single version or version range:

*

7.3 - 8.1, 7.3, 7.4

*

This field is currently unused, but logic for checking if a version is included is present.

*/ private final String supportedPhpVersions; /** *

This is the version of the Java Development Kit (JDK) for the given product cycle that has to be used to run the * product.

*

Example: https://endoflife.date/azul-zulu

*/ private final String latestJdkVersion; /** *

Currently, only the amazon-neptune product uses this field. In this one case, * it is a string containing the version that the product will automatically be upgraded to during a maintenance window.

*/ private final String upgradeVersion; /** *

Contains a formatted name for the release. May contain HTML content and the same expression evaluator as the link key. * Examples:

*
    *
  • AMI 2016.03
  • *
  • Core __RELEASE_CYCLE__
  • *
  • OS X __RELEASE_CYCLE__ (__CODENAME__)
  • *
  • 9 (<abbr title='Short Term Support'>STS<\/abbr>)
  • *
*/ private final String releaseLabel; /** * @see #supportedPhpVersions */ private final String supportedKubernetesVersions; /** * @see #supportedPhpVersions */ private final String supportedJavaVersions; private final String minRubyVersion; /** *

An alternate (project internal) name for the version. Example is android with their dessert names:

*

     * {
     *   "product": "android",
     *   "codename": "Queen Cake",
     *   "cycle": "10"
     * }
     * 
*/ private final String codename; private final String minJavaVersion; public EolCycle(String product, String cycle, String releaseDate, String eol, String latest, String link, String lts, String support, String discontinued, String latestReleaseDate, String supportedPhpVersions, String latestJdkVersion, String extendedSupport, String upgradeVersion, String releaseLabel, String supportedKubernetesVersions, String minRubyVersion, String codename, String technicalGuidance, String supportedJavaVersions, String minJavaVersion) { this.product = product; this.cycle = cycle; this.releaseDate = releaseDate; this.eol = eol; this.latest = latest; this.lts = lts; this.support = support; this.discontinued = discontinued; this.latestReleaseDate = latestReleaseDate; this.supportedPhpVersions = supportedPhpVersions; this.latestJdkVersion = latestJdkVersion; this.extendedSupport = extendedSupport; this.upgradeVersion = upgradeVersion; this.supportedKubernetesVersions = supportedKubernetesVersions; this.minRubyVersion = minRubyVersion; this.codename = codename; this.technicalGuidance = technicalGuidance; this.supportedJavaVersions = supportedJavaVersions; this.minJavaVersion = minJavaVersion; this.link = EolStringFormatter.format(link, this); this.releaseLabel = EolStringFormatter.format(releaseLabel, this); } public EolCycle(String product, String cycle) { this(product, cycle, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null); } public LtsState getLtsState() { return new StateMapping<>(LtsState.NOT_LTS, LtsState.LTS, LtsState.LTS_DATE_REACHED, LtsState.UPCOMING_LTS_DATE, false, "lts") .getState(lts, 0); } public DiscontinuedState getDiscontinuedState() { return new StateMapping<>(DiscontinuedState.NOT_DISCONTINUED, DiscontinuedState.DISCONTINUED, DiscontinuedState.DISCONTINUED_DATE_REACHED, DiscontinuedState.UPCOMING_DISCONTINUED_DATE, false, "discontinued") .getState(discontinued, 0); } public EolState getEolState() { return getEolState(0); } public EolState getEolState(long millisUntilEolWarning) { return new StateMapping<>(EolState.NOT_EOL, EolState.EOL, EolState.EOL_DATE_REACHED, EolState.DISTANT_EOL_DATE, EolState.UPCOMING_EOL_DATE, false, "eol") .getState(eol, millisUntilEolWarning); } public SupportState getSupportState() { return getSupportState(0); } public SupportState getSupportState(long millisUntilSupportEndWarning) { if (StringUtils.isEmpty(support)) { return SupportState.fromEolState(getEolState(millisUntilSupportEndWarning)); } return new StateMapping<>(SupportState.NO_SUPPORT, SupportState.SUPPORT, SupportState.SUPPORT_END_DATE_REACHED, SupportState.DISTANT_SUPPORT_END_DATE, SupportState.UPCOMING_SUPPORT_END_DATE, false, "support") .getState(support, millisUntilSupportEndWarning); } public SupportState getExtendedSupportState() { return getExtendedSupportState(0); } public SupportState getExtendedSupportState(long millisUntilExtendedSupportEndWarning) { // must also check for false, see "angular" product where there are three columns if (StringUtils.isEmpty(extendedSupport) || extendedSupport.equals("false")) { final EolState eolState = getEolState(millisUntilExtendedSupportEndWarning); if (eolState == EolState.UPCOMING_EOL_DATE || eolState == EolState.EOL_DATE_REACHED || eolState == EolState.DISTANT_EOL_DATE) { if ("false".equals(support)) { return SupportState.fromEolState(eolState); } final Date eolDate = TimeUtils.tryParse(eol); final Date supportDate = TimeUtils.tryParse(support); if (eolDate != null && supportDate != null) { if (eolDate.after(supportDate)) { return SupportState.fromEolState(eolState); } else { return SupportState.NO_SUPPORT; } } } else if (eolState == EolState.NOT_EOL) { return SupportState.SUPPORT; } } return new StateMapping<>(SupportState.NO_SUPPORT, SupportState.SUPPORT, SupportState.SUPPORT_END_DATE_REACHED, SupportState.DISTANT_SUPPORT_END_DATE, SupportState.UPCOMING_SUPPORT_END_DATE, false, "support") .getState(extendedSupport, millisUntilExtendedSupportEndWarning); } public TechnicalGuidanceState getTechnicalGuidanceState() { return new StateMapping<>(TechnicalGuidanceState.NO_TECHNICAL_GUIDANCE, TechnicalGuidanceState.TECHNICAL_GUIDANCE, TechnicalGuidanceState.END_OF_TECHNICAL_GUIDANCE_DATE_REACHED, TechnicalGuidanceState.UPCOMING_END_OF_TECHNICAL_GUIDANCE_DATE, false, "technicalGuidance") .getState(technicalGuidance, 0); } public String getSupport() { if (StringUtils.isEmpty(support)) { final EolState eolState = getEolState(); switch (eolState) { case EOL: return "false"; case NOT_EOL: return "true"; case EOL_DATE_REACHED: case UPCOMING_EOL_DATE: case DISTANT_EOL_DATE: default: return eol; } } else { return support; } } public String getExtendedSupport() { if (StringUtils.isEmpty(extendedSupport)) { if (Objects.equals(support, eol)) { return extendedSupport; } final EolState eolState = getEolState(); if (eolState == EolState.UPCOMING_EOL_DATE || eolState == EolState.EOL_DATE_REACHED || eolState == EolState.DISTANT_EOL_DATE) { if ("false".equals(support)) { return eol; } final Date eolDate = TimeUtils.tryParse(eol); final Date supportDate = TimeUtils.tryParse(support); if (eolDate != null && supportDate != null) { if (eolDate.after(supportDate)) { return eol; } else { return "false"; } } } } return extendedSupport; } public boolean isExtendedSupportGenerallyAvailable() { return !StringUtils.isEmpty(getExtendedSupport()); } public long getTimeUntilSupportEnd() { return getTimeUntil(getSupport(), true); } /** * Formats the time until a specific date or the time ago from a specific date. * * @param timeUntil the time until a specific date in milliseconds * @return a formatted string representing the time until or ago from the specific date * @see TimeUtils#formatTimeUntilOrAgo(long, String, String, String, String, String, String) */ public static String formatTimeUntilOrAgo(long timeUntil) { return TimeUtils.formatTimeUntilOrAgo(timeUntil, "", "in", "ago", "", " and ", "no date provided"); } public long getTimeUntilExtendedSupportEnd() { return getTimeUntil(getExtendedSupport(), true); } public long getTimeUntilTechnicalGuidanceEnd() { return getTimeUntil(technicalGuidance, true); } public long getTimeUntilEol() { return getTimeUntil(eol, false); } public long getTimeUntilDiscontinued() { return getTimeUntil(discontinued, true); } public long getTimeUntilLtsStart() { return getTimeUntil(lts, false); } /** * Either string<date> or string<boolean>.
*
    *
  • "true" - Long.MAX_VALUE if trueIsMax is true, 0 otherwise
  • *
  • "false" - 0 if trueIsMax is true, Long.MAX_VALUE otherwise
  • *
  • "YYYY-MM-DD" - milliseconds until that date
  • *
* * @param dateString string<date> or string<boolean> * @return milliseconds until that date, see above */ private long getTimeUntil(String dateString, boolean trueIsMax) { if (StringUtils.isEmpty(dateString)) { return Long.MAX_VALUE; } if ("true".equals(dateString)) { return trueIsMax ? Long.MAX_VALUE : 0; } else if ("false".equals(dateString)) { return trueIsMax ? 0 : Long.MAX_VALUE; } final Date date = TimeUtils.tryParse(dateString); if (date == null) { return 0; } return date.getTime() - StateMapping.getNOW().getTime(); } public JSONObject toJson() { JSONObject json = new JSONObject(); putIfNotNull(json, "product", product); putIfNotNull(json, "cycle", cycle); putIfNotNull(json, "releaseDate", releaseDate); putIfNotNull(json, "eol", eol); putIfNotNull(json, "latest", latest); putIfNotNull(json, "link", link); putIfNotNull(json, "lts", lts); putIfNotNull(json, "support", support); putIfNotNull(json, "discontinued", discontinued); putIfNotNull(json, "latestReleaseDate", latestReleaseDate); putIfNotNull(json, "supportedPhpVersions", supportedPhpVersions); putIfNotNull(json, "latestJdkVersion", latestJdkVersion); putIfNotNull(json, "extendedSupport", extendedSupport); putIfNotNull(json, "upgradeVersion", upgradeVersion); putIfNotNull(json, "releaseLabel", releaseLabel); putIfNotNull(json, "supportedKubernetesVersions", supportedKubernetesVersions); putIfNotNull(json, "minRubyVersion", minRubyVersion); putIfNotNull(json, "supportedPHPVersions", supportedPhpVersions); putIfNotNull(json, "codename", codename); putIfNotNull(json, "technicalGuidance", technicalGuidance); putIfNotNull(json, "supportedJavaVersions", supportedJavaVersions); putIfNotNull(json, "minJavaVersion", minJavaVersion); return json; } public Document toDocument() { final Document document = new Document(); addFieldToDocument(document, "product", product); addFieldToDocument(document, "cycle", cycle); addFieldToDocument(document, "releaseDate", releaseDate); addFieldToDocument(document, "eol", eol); addFieldToDocument(document, "latest", latest); addFieldToDocument(document, "link", link); addFieldToDocument(document, "lts", lts); addFieldToDocument(document, "support", support); addFieldToDocument(document, "discontinued", discontinued); addFieldToDocument(document, "latestReleaseDate", latestReleaseDate); addFieldToDocument(document, "supportedPhpVersions", supportedPhpVersions); addFieldToDocument(document, "latestJdkVersion", latestJdkVersion); addFieldToDocument(document, "extendedSupport", extendedSupport); addFieldToDocument(document, "upgradeVersion", upgradeVersion); addFieldToDocument(document, "releaseLabel", releaseLabel); addFieldToDocument(document, "supportedKubernetesVersions", supportedKubernetesVersions); addFieldToDocument(document, "minRubyVersion", minRubyVersion); addFieldToDocument(document, "supportedPHPVersions", supportedPhpVersions); addFieldToDocument(document, "codename", codename); addFieldToDocument(document, "technicalGuidance", technicalGuidance); addFieldToDocument(document, "supportedJavaVersions", supportedJavaVersions); addFieldToDocument(document, "minJavaVersion", minJavaVersion); return document; } public static EolCycle fromJson(JSONObject json) { return new EolCycle( parseJson(json, "product"), parseJson(json, "cycle"), parseJson(json, "releaseDate"), parseJson(json, "eol"), parseJson(json, "latest"), parseJson(json, "link"), parseJson(json, "lts"), parseJson(json, "support"), parseJson(json, "discontinued"), parseJson(json, "latestReleaseDate"), firstNonNull(parseJson(json, "supportedPhpVersions"), parseJson(json, "supportedPHPVersions")), parseJson(json, "latestJdkVersion"), parseJson(json, "extendedSupport"), parseJson(json, "upgradeVersion"), parseJson(json, "releaseLabel"), parseJson(json, "supportedKubernetesVersions"), parseJson(json, "minRubyVersion"), parseJson(json, "codename"), parseJson(json, "technicalGuidance"), parseJson(json, "supportedJavaVersions"), parseJson(json, "minJavaVersion")); } public static EolCycle fromDocument(Document e) { return new EolCycle( e.get("product"), e.get("cycle"), e.get("releaseDate"), e.get("eol"), e.get("latest"), e.get("link"), e.get("lts"), e.get("support"), e.get("discontinued"), e.get("latestReleaseDate"), firstNonNull(e.get("supportedPhpVersions"), e.get("supportedPHPVersions")), e.get("latestJdkVersion"), e.get("extendedSupport"), e.get("upgradeVersion"), e.get("releaseLabel"), e.get("supportedKubernetesVersions"), e.get("minRubyVersion"), e.get("codename"), e.get("technicalGuidance"), e.get("supportedJavaVersions"), e.get("minJavaVersion")); } /** * The default comparator for EolCycle objects. *

* This comparator defines the default sorting order for EolCycle objects. It first compares * the products using their natural order. If the products are equal, it then compares the * cycles using the VersionComparator.INSTANCE.compare() method. Next, it compares the * release dates, followed by the EOL dates. If the EOL dates are equal, it compares the latest * versions using the VersionComparator.INSTANCE.compare() method. Finally, it compares the * links and LTS values. *

* Usually, the cycle is already a unique value within a product, but just to be sure, other attributes are used. * * @see EolCycle * @see VersionComparator */ private final static Comparator DEFAULT_COMPARATOR = Comparator.comparing(EolCycle::getProduct, Comparator.nullsLast(Comparator.naturalOrder())) .thenComparing((o1, o2) -> { if (o1.getCycle() == null || o2.getCycle() == null) { return 0; } return VersionComparator.INSTANCE.compare(o1.getCycle(), o2.getCycle()); }) .thenComparing(EolCycle::getReleaseDate, Comparator.nullsLast(Comparator.naturalOrder())) .thenComparing(EolCycle::getEol, Comparator.nullsLast(Comparator.naturalOrder())) .thenComparing((o1, o2) -> { if (o1.getLatest() == null || o2.getLatest() == null) { return 0; } return VersionComparator.INSTANCE.compare(o1.getLatest(), o2.getLatest()); }) .thenComparing(EolCycle::getLink, Comparator.nullsLast(Comparator.naturalOrder())) .thenComparing(EolCycle::getLts, Comparator.nullsLast(Comparator.naturalOrder())); @Override public int compareTo(EolCycle o) { return DEFAULT_COMPARATOR.compare(this, o); } private static String parseJson(JSONObject json, String key) { Object obj = json.opt(key); if (obj instanceof Boolean) { return Boolean.toString((Boolean) obj); } else if (obj != null && !obj.toString().equals("null")) { return obj.toString(); } else { return null; } } private void putIfNotNull(JSONObject json, String key, String value) { if (value != null && !value.equals("null")) { json.put(key, value); } } private void addFieldToDocument(Document document, String fieldName, String fieldValue) { if (fieldValue != null && !fieldValue.equals("null")) { document.add(new TextField(fieldName, fieldValue, Field.Store.YES)); } } public void setProduct(String product) { this.product = product; } public String getProduct() { return product; } public String getCycle() { return cycle; } public String getReleaseDate() { return releaseDate; } public String getEol() { return eol; } public String getLatest() { return latest; } public String getLink() { return link; } public String getLts() { return lts; } public String getDiscontinued() { return discontinued; } public String getLatestReleaseDate() { return latestReleaseDate; } public String getSupportedPhpVersions() { return supportedPhpVersions; } public String getLatestJdkVersion() { return latestJdkVersion; } public String getUpgradeVersion() { return upgradeVersion; } public String getReleaseLabel() { return releaseLabel; } public String getSupportedKubernetesVersions() { return supportedKubernetesVersions; } public String getMinRubyVersion() { return minRubyVersion; } public String getCodename() { return codename; } public String getTechnicalGuidance() { return technicalGuidance; } public String getSupportedJavaVersions() { return supportedJavaVersions; } public String getMinJavaVersion() { return minJavaVersion; } @Override public String toString() { return toJson().toString(); } /** * @param checkVersion The version to check for * @return -1 if the version is not in the cycle, the higher a positive number is, the more the version matches. */ public int matchVersion(String checkVersion) { if (checkVersion == null) { return -1; } if (checkVersion.equals(latest)) { return Integer.MAX_VALUE; } final String normalizedVersion = normalizeVersionForComparison(checkVersion); final String normalizedCycle = normalizeVersionForComparison(cycle); final String normalizedReleaseLabel = normalizeVersionForComparison(releaseLabel); final boolean cycleDefined = normalizedCycle != null; final boolean releaseLabelDefined = normalizedReleaseLabel != null; if (cycleDefined && normalizedVersion.startsWith(normalizedCycle)) { return normalizedCycle.length(); } else if (releaseLabelDefined && normalizedVersion.startsWith(normalizedReleaseLabel)) { return normalizedReleaseLabel.length(); } if (cycleDefined && normalizedCycle.startsWith(normalizedVersion)) { return normalizedVersion.length(); } else if (releaseLabelDefined && normalizedReleaseLabel.startsWith(normalizedVersion)) { return normalizedVersion.length(); } final Version checkVersionInstance = Version.of(checkVersion); if (cycleDefined) { final Version cycleVersionInstance = Version.of(cycle); if (cycleVersionInstance.matchesVersionOf(checkVersionInstance)) { return Integer.MAX_VALUE; } } else if (releaseLabelDefined) { final Version releaseLabelVersionInstance = Version.of(releaseLabel); if (releaseLabelVersionInstance.matchesVersionOf(checkVersionInstance)) { return Integer.MAX_VALUE; } } return -1; } private String normalizeVersionForComparison(String version) { if (version == null) { return null; } if (version.startsWith("v")) { version = version.substring(1); } version = version.toLowerCase(); version = version.replaceAll("[^a-z0-9.]", ""); return version; } /** * Checks if the provided PHP version is contained within the supported PHP versions.
* Example: 7.3 is contained in 7.3 - 8.1, 7.3, 7.4 * * @param version The PHP version to check. * @return True if the PHP version is contained within the supported PHP versions, false otherwise. */ public boolean containsPhpVersion(String version) { return containsSupportedVersion(version, supportedPhpVersions); } public boolean containsKubernetesVersion(String version) { return containsSupportedVersion(version, supportedKubernetesVersions); } public boolean containsJavaVersion(String version) { return containsSupportedVersion(version, supportedJavaVersions); } /** * Checks if the provided version is contained within the supported versions.
* Example: 7.3 is contained in 7.3 - 8.1, 7.3, 7.4 * * @param version The version to check. * @param supportedVersions A string containing the supported versions separated by commas. * @return True if the version is contained within the supported versions, false otherwise. */ private boolean containsSupportedVersion(String version, String supportedVersions) { if (version == null) { return false; } else if (supportedVersions == null) { return false; } final String[] versions = supportedVersions.split(", ?"); for (String ver : versions) { if (checkIfSingleVersionIsContained(ver, version)) { return true; } } return false; } /** * Checks if a single version is contained within a given part.
* Example: 7.3 is contained in "7.3 - 8.1" and "7.3" * * @param part The part to check, which can be a single version or a range of versions. * @param version The PHP version to check against the part. * @return True if the PHP version is contained within the part, false otherwise. */ private boolean checkIfSingleVersionIsContained(String part, String version) { if (part.contains(" - ")) { final String[] range = part.split(" - "); if (range.length != 2) { return false; } return VersionComparator.INSTANCE.compare(range[0], version) <= 0 && VersionComparator.INSTANCE.compare(range[1], version) >= 0; } else { return version.startsWith(part); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy