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

com.helger.diver.api.version.DVRVersion Maven / Gradle / Ivy

/*
 * Copyright (C) 2023-2024 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * 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.helger.diver.api.version;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.MustImplementComparable;
import com.helger.commons.annotation.MustImplementEqualsAndHashcode;
import com.helger.commons.annotation.Nonempty;
import com.helger.commons.collection.impl.CommonsLinkedHashSet;
import com.helger.commons.collection.impl.ICommonsSet;
import com.helger.commons.equals.EqualsHelper;
import com.helger.commons.hashcode.HashCodeGenerator;
import com.helger.commons.string.StringHelper;
import com.helger.commons.string.ToStringGenerator;
import com.helger.commons.version.Version;
import com.helger.diver.api.settings.DVRValidityHelper;

/**
 * This class contains the version of a DVR Coordinate. This can either be a
 * static version or a pseudo version. This version type has a specific kind of
 * ordering, so that versions using the classifier "SNAPSHOT" are ordered BEFORE
 * respective release versions. Example order:
 * 
    *
  1. 1.0
  2. *
  3. 1.1-SNAPSHOT
  4. *
  5. 1.1
  6. *
  7. 1.2
  8. *
  9. 1.3-SNAPSHOT
  10. *
  11. 1.3
  12. *
* * @author Philip Helger */ @Immutable @MustImplementComparable @MustImplementEqualsAndHashcode public final class DVRVersion implements Comparable { /** Specific qualifier for "SNAPSHOT" versions" */ public static final String QUALIFIER_SNAPSHOT = "SNAPSHOT"; /** Separator between major and minor and between minor and micro version */ public static final char NUMERIC_VERSION_PART_SEPARATOR = '.'; /** Separate between classifier and the rest (if available) */ public static final char DEFAULT_CLASSIFIER_SEPARATOR = '-'; private static final Logger LOGGER = LoggerFactory.getLogger (DVRVersion.class); private final Version m_aStaticVersion; private final IDVRPseudoVersion m_aPseudoVersion; /** * Constructor - only invoked by the static factory methods below * * @param aStaticVersion * Static version. May be null. * @param aPseudoVersion * Pseudo version. May be null. */ private DVRVersion (@Nullable final Version aStaticVersion, @Nullable final IDVRPseudoVersion aPseudoVersion) { ValueEnforcer.isTrue (aStaticVersion != null || aPseudoVersion != null, "Either Static Version or Pseudo Version must be provided"); ValueEnforcer.isFalse (aStaticVersion != null && aPseudoVersion != null, "Only one of Static Version or Pseudo Version must be provided"); m_aStaticVersion = aStaticVersion; m_aPseudoVersion = aPseudoVersion; } /** * @return true if it is a static version, false if * it is a pseudo version * @see #isPseudoVersion() * @see #getStaticVersion() */ public boolean isStaticVersion () { return m_aStaticVersion != null; } /** * @param sQualifier * The qualifier to check. May be null., * @return true if the qualifier is "SNAPSHOT". * @since 3.0.0 */ public static boolean isStaticSnapshotVersion (@Nullable final String sQualifier) { return QUALIFIER_SNAPSHOT.equals (sQualifier); } /** * @param aVer * The version to check. May be null., * @return true if the passed version has the the qualifier * "SNAPSHOT". * @since 1.0.1 */ public static boolean isStaticSnapshotVersion (@Nullable final Version aVer) { return aVer != null && isStaticSnapshotVersion (aVer.getQualifier ()); } /** * @return true if this is a static version, and if the qualifier * is "SNAPSHOT". * @see #isStaticVersion() */ public boolean isStaticSnapshotVersion () { return isStaticSnapshotVersion (m_aStaticVersion); } /** * @return The static version of this VER version. Guaranteed to be * non-null if {@link #isStaticVersion()} returns true. * @see #isStaticVersion() */ @Nullable public Version getStaticVersion () { return m_aStaticVersion; } /** * @return true if it is a pseudo version, false if * it is a static version * @see #isStaticVersion() * @see #getPseudoVersion() */ public boolean isPseudoVersion () { return m_aPseudoVersion != null; } /** * @return The pseudo version of this VER version. Guaranteed to be * non-null if {@link #isPseudoVersion()} returns true. * @see #isPseudoVersion() */ @Nullable public IDVRPseudoVersion getPseudoVersion () { return m_aPseudoVersion; } @Nonnull private static String _getAsString (@Nonnull final Version aVersion, final char cClassifierSep, final boolean bEnforceAllNumbers, final boolean bEnforceAtLeastMinor) { // Different implementation then Version.getAsString (...) String ret = ""; char cSep = cClassifierSep; boolean bMust = bEnforceAllNumbers; // Start from the back: classifier if (aVersion.hasQualifier ()) ret = aVersion.getQualifier (); // Add micro version if (aVersion.getMicro () > 0 || bMust) { if (!ret.isEmpty ()) ret = cSep + ret; ret = aVersion.getMicro () + ret; // Change separator to number version separator cSep = NUMERIC_VERSION_PART_SEPARATOR; bMust = true; } if (bEnforceAtLeastMinor) bMust = true; // Add minor version if (aVersion.getMinor () > 0 || bMust) { if (!ret.isEmpty ()) ret = cSep + ret; ret = aVersion.getMinor () + ret; // Change separator to number version separator cSep = '.'; bMust = true; } // Add major version // Avoid empty string if (aVersion.getMajor () > 0 || bMust || ret.isEmpty ()) { if (!ret.isEmpty ()) ret = cSep + ret; ret = aVersion.getMajor () + ret; } return ret; } @Nonnull public static String getAsString (@Nonnull final Version aVersion) { return _getAsString (aVersion, DEFAULT_CLASSIFIER_SEPARATOR, false, false); } @Nonnull @Nonempty public static String getAsString (@Nonnull final IDVRPseudoVersion aPseudoVersion) { return aPseudoVersion.getID (); } /** * @return The unified string representation of the Version. */ @Nonnull public String getAsString () { if (m_aStaticVersion != null) return getAsString (m_aStaticVersion); return getAsString (m_aPseudoVersion); } @Nonnull private static Version _getWithoutQualifier (@Nonnull final Version aSrc) { return new Version (aSrc.getMajor (), aSrc.getMinor (), aSrc.getMicro (), null); } private static int _compareSemantically (@Nonnull final Version aLhs, @Nonnull final Version aRhs) { if (QUALIFIER_SNAPSHOT.equals (aLhs.getQualifier ())) { if (QUALIFIER_SNAPSHOT.equals (aRhs.getQualifier ())) { // Lhs & Rhs are Snapshots return aLhs.compareTo (aRhs); } // Lhs is Snapshot final Version aLhsClean = _getWithoutQualifier (aLhs); final int nCmp = aLhsClean.compareTo (aRhs); if (nCmp == 0) { // Snapshots comes before release return -1; } return nCmp; } if (QUALIFIER_SNAPSHOT.equals (aRhs.getQualifier ())) { // Rhs is Snapshot final Version aRhsClean = _getWithoutQualifier (aRhs); final int nCmp = aLhs.compareTo (aRhsClean); if (nCmp == 0) { // Snapshots comes before release return +1; } return nCmp; } // No snapshot version contained return aLhs.compareTo (aRhs); } /** * Compare a static version with a pseudo version * * @param aStaticVersion * Static version. May not be null. * @param aPseudoVersion * Pseudo version. May not be null. * @return -1, 0 or +1 */ private static int _compareWithPseudoVersion (@Nonnull final Version aStaticVersion, @Nonnull final IDVRPseudoVersion aPseudoVersion) { // Change sign, due to calling order return -aPseudoVersion.compareToVersion (aStaticVersion); } public int compareTo (@Nonnull final DVRVersion rhs) { if (isStaticVersion ()) { if (rhs.isStaticVersion ()) return _compareSemantically (m_aStaticVersion, rhs.m_aStaticVersion); return _compareWithPseudoVersion (m_aStaticVersion, rhs.m_aPseudoVersion); } // this is a pseudo version if (rhs.isStaticVersion ()) { // Invert result return -_compareWithPseudoVersion (rhs.m_aStaticVersion, m_aPseudoVersion); } // Both are psudo versions return m_aPseudoVersion.compareToPseudoVersion (rhs.m_aPseudoVersion); } @Override public boolean equals (final Object o) { if (o == this) return true; if (o == null || !getClass ().equals (o.getClass ())) return false; final DVRVersion rhs = (DVRVersion) o; return EqualsHelper.equals (m_aStaticVersion, rhs.m_aStaticVersion) && EqualsHelper.equals (m_aPseudoVersion, rhs.m_aPseudoVersion); } @Override public int hashCode () { return new HashCodeGenerator (this).append (m_aStaticVersion).append (m_aPseudoVersion).getHashCode (); } @Override public String toString () { return new ToStringGenerator (null).appendIfNotNull ("StaticVersion", m_aStaticVersion) .appendIfNotNull ("PseudoVersion", m_aPseudoVersion) .getToString (); } @Nonnull public static DVRVersion of (@Nonnull final Version aVersion) { ValueEnforcer.notNull (aVersion, "Version"); return new DVRVersion (aVersion, null); } @Nonnull public static DVRVersion of (@Nonnull final IDVRPseudoVersion aPseudoVersion) { ValueEnforcer.notNull (aPseudoVersion, "PseudoVersion"); return new DVRVersion (null, aPseudoVersion); } /** * Checks if the provided version is a valid static version. *
    *
  • 1.0.0
  • *
  • 1.0
  • *
  • 1
  • *
  • 1.0.0-SNAPSHOT
  • *
  • 1.0-SNAPSHOT
  • *
  • 1-SNAPSHOT
  • *
  • 1.0.0.SNAPSHOT
  • *
  • 1.0.SNAPSHOT
  • *
  • 1.SNAPSHOT
  • *
* * @param sVersion * The version to check * @return true if the version is a valid static version, * false if not. */ public static boolean isValidStaticVersion (@Nullable final String sVersion) { // Must not be empty if (StringHelper.hasNoText (sVersion)) return false; // Must follow the DVR Coordinate constraints if (!DVRValidityHelper.isValidCoordinateVersion (sVersion)) return false; // Parse to Version object final Version aParsedVersion = Version.parse (sVersion); if (aParsedVersion == null) return false; // Check if the parsing result equals the original in a way // This section clearly would win the price for ugly coding - but the // positive effect on consistency is even more valuable :) final ICommonsSet aPossibleVersions = new CommonsLinkedHashSet <> (); // Check different separators for (final char c : "-.".toCharArray ()) for (final boolean bEnforceAllNumbers : new boolean [] { true, false }) for (final boolean bEnforceMinor : new boolean [] { true, false }) { final String sText = _getAsString (aParsedVersion, c, bEnforceAllNumbers, bEnforceMinor); if (sVersion.equals (sText)) return true; aPossibleVersions.add (sText); } if (LOGGER.isDebugEnabled ()) LOGGER.debug ("'" + sVersion + "' is none of " + StringHelper.imploder () .source (aPossibleVersions, x -> "'" + x + "'") .separator (" or ") .build ()); // Nope return false; } @Nonnull public static DVRVersion parseOrThrow (@Nullable final String sVersion) throws DVRVersionException { if (StringHelper.hasNoText (sVersion)) throw new DVRVersionException ("DVR Version string must not be empty"); // Check pseudo version first final IDVRPseudoVersion ePseudoVersion = DVRPseudoVersionRegistry.getInstance ().getFromIDOrNull (sVersion); if (ePseudoVersion != null) return of (ePseudoVersion); if (isValidStaticVersion (sVersion)) { // Try to convert into a Version object instead return of (Version.parse (sVersion)); } throw new DVRVersionException ("Failed to parse '" + sVersion + "' to a DVR Version"); } @Nullable public static DVRVersion parseOrNull (@Nullable final String sVersion) { try { return parseOrThrow (sVersion); } catch (final DVRVersionException | RuntimeException ex) { LOGGER.warn (ex.getMessage ()); return null; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy