blob: 7967e8b4fb3aa2dfe56735b0b1f7077115dad51b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2017 Cloudsmith and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Cloudsmith Inc - initial API and implementation.
*******************************************************************************/
package org.eclipse.equinox.p2.metadata;
import java.io.Serializable;
import java.lang.ref.SoftReference;
import java.util.WeakHashMap;
import org.eclipse.equinox.internal.p2.metadata.*;
/**
* A class that represents a Version in the Omni Version format. A Version can be thought of as an
* array of comparable elements and an optional pad value. The pad value is used when comparing
* two versions with a different number of segments.
*
* The Omni Version can convert almost any version into a raw format that it uses for comparisons.
* This enables a unified order of all such versions and solves problems that arise when the
* version semantics are different. A good example is the OSGi version versus the version used in Maven.
* The lack of qualifier in the OSGi version implies that the qualifier is an empty string. So a version
* without a qualifier is the smallest of all other versions with the same major,minor,micro number.
* With Maven semantics, it's the opposite. If the qualifier is removed, the resulting version is
* considered higher then all other versions with the same major, minor, and micro number. The
* Omni version solves this by using different raw representations of the OSGi and Maven versions.
*
* The Omni version addresses a lot of other issues as well, such as reordering of the elements
* or treating some parts of a version as irrelevant when comparing.
*
* The class is signature compatible with {@link org.osgi.framework.Version} but attempts
* to use it as such might render a {@link UnsupportedOperationException} in case the
* raw vector holds incompatible values. The method {@link #isOSGiCompatible()} can be used
* to test.
* @noextend This class is not intended to be subclassed by clients.
* @since 2.0
*/
public abstract class Version implements Comparable<Version>, Serializable {
public static final String RAW_PREFIX = "raw:"; //$NON-NLS-1$
private static WeakHashMap<String, SoftReference<Version>> POOL = new WeakHashMap<>();
/**
* The version that is semantically greater then all other versions.
*/
public static final Version MAX_VERSION = OmniVersion.createMaxVersion();
/**
* The version that is semantically less then all other versions.
*/
public static final Version emptyVersion = OmniVersion.createMinVersion();
private static final long serialVersionUID = 6218979149720923857L;
/**
* Compile a version format string into a compiled format..
*
* @param format The format to compile.
* @return The compiled format
* @throws VersionFormatException If the format could not be compiled
*/
public static IVersionFormat compile(String format) throws VersionFormatException {
return VersionFormat.compile(format, 0, format.length());
}
/**
* Parses a version identifier from the specified string.
* <p>
* Note that this method performs a non thread-safe object pooling. Instances are
* stored in a weak cache, i.e. for multiple calls with the same input it is likely
* but not guaranteed that the same instance is retrieved. Same holds for concurrent
* access on this method. Clients must not assume to get the same instance for
* subsequent calls.
*
* @param version String representation of the version identifier. Leading
* and trailing whitespace will be ignored.
* @return A <code>Version</code> object representing the version identifier
* or <code>null</code> if <code>version</code> is <code>null</code> or
* an empty string.
* @throws IllegalArgumentException If <code>version</code> is improperly
* formatted.
*/
public static Version create(String version) {
Version v = null;
if (version != null && version.length() > 0) {
SoftReference<Version> vRef = POOL.get(version);
v = vRef != null ? vRef.get() : null;
if (v == null) {
v = VersionParser.parse(version, 0, version.length());
synchronized (POOL) {
POOL.put(version, new SoftReference<>(v));
}
}
}
return v;
}
/**
* Creates an OSGi version identifier from the specified numerical components.
*
* <p>
* The qualifier is set to the empty string.
*
* @param major Major component of the version identifier.
* @param minor Minor component of the version identifier.
* @param micro Micro component of the version identifier.
* @throws IllegalArgumentException If the numerical components are
* negative.
*/
public static Version createOSGi(int major, int minor, int micro) {
return createOSGi(major, minor, micro, null);
}
/**
* Creates an OSGi version identifier from the specified components.
*
* @param major Major component of the version identifier.
* @param minor Minor component of the version identifier.
* @param micro Micro component of the version identifier.
* @param qualifier Qualifier component of the version identifier. If
* <code>null</code> is specified, then the qualifier will be set to
* the empty string.
* @throws IllegalArgumentException If the numerical components are negative
* or the qualifier string is invalid.
*/
public static Version createOSGi(int major, int minor, int micro, String qualifier) {
Comparable<?> logicQualifier;
if (qualifier == null || qualifier.length() == 0) {
if (major == 0 && minor == 0 && micro == 0)
return emptyVersion;
logicQualifier = VersionVector.MINS_VALUE; // So that we can do identity compare
} else if (qualifier.equals(IVersionFormat.DEFAULT_MAX_STRING_TRANSLATION))
logicQualifier = VersionVector.MAXS_VALUE;
else
logicQualifier = qualifier;
return new OSGiVersion(major, minor, micro, logicQualifier);
}
/**
* Parses a version identifier from the specified string. This method is for backward
* compatibility with OSGi and will return the OSGi &quot;0.0.0&quot; version when
* the provided string is empty or <code>null</code>.
*
* @param version String representation of the version identifier. Leading
* and trailing whitespace will be ignored.
* @return A <code>Version</code> object representing the version
* identifier. If <code>version</code> is <code>null</code> or
* the empty string then the OSGi <code>emptyVersion</code> will be
* returned.
* @throws IllegalArgumentException If <code>version</code> is improperly
* formatted.
* @see #create(String)
*/
public static Version parseVersion(String version) {
if (version == null || version.length() == 0)
return Version.emptyVersion;
Version v = create(version);
return v == null ? Version.emptyVersion : v;
}
/**
* Returns the optional format.
*/
public abstract IVersionFormat getFormat();
/**
* Returns the <code>original</code> part of the string for this version
* or <code>null</code> if no such part was provided when the version was
* created. An OSGi type version will always return the OSGi string representation.
*
* @return The <code>original</code> part of the version string or
* <code>null</code> if that part was missing.
*/
public abstract String getOriginal();
/**
* Returns the pad value used when comparing this versions to
* versions that has a larger number of segments
* @return The pad value or <code>null</code> if not set.
*/
public abstract Comparable<?> getPad();
/**
* An element from the raw vector representation of this version.
* @param index The zero based index of the desired element
* @return An element from the raw vector
*/
public abstract Comparable<?> getSegment(int index);
/**
* Returns the number of elements in the raw vector representation of this version.
* @return The number of elements in the raw vector.
*/
public abstract int getSegmentCount();
/**
* Checks if this version is in compliance with the OSGi version spec.
* @return A flag indicating whether the version is OSGi compatible or not.
*/
public abstract boolean isOSGiCompatible();
@Override
public String toString() {
StringBuffer buf = new StringBuffer(20);
toString(buf);
return buf.toString();
}
/**
* Appends the string representation of this version onto the
* <code>sb</code> StringBuffer.
* @param sb The buffer that will receive the version string
*/
public abstract void toString(StringBuffer sb);
}