blob: aa0eff73888f10a38ed563d0577947062d12dd3f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Sergey Prigogin (Google) - use parameterized types (bug 442021)
*******************************************************************************/
package org.eclipse.core.runtime;
import java.util.StringTokenizer;
import java.util.Vector;
import org.eclipse.core.internal.runtime.CommonMessages;
import org.eclipse.core.internal.runtime.IRuntimeConstants;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.Version;
/**
* <p>
* Version identifier for a plug-in. In its string representation,
* it consists of up to 4 tokens separated by a decimal point.
* The first 3 tokens are positive integer numbers, the last token
* is an uninterpreted string (no whitespace characters allowed).
* For example, the following are valid version identifiers
* (as strings):
* <ul>
* <li><code>0.0.0</code></li>
* <li><code>1.0.127564</code></li>
* <li><code>3.7.2.build-127J</code></li>
* <li><code>1.9</code> (interpreted as <code>1.9.0</code>)</li>
* <li><code>3</code> (interpreted as <code>3.0.0</code>)</li>
* </ul>
* </p>
* <p>
* The version identifier can be decomposed into a major, minor,
* service level component and qualifier components. A difference
* in the major component is interpreted as an incompatible version
* change. A difference in the minor (and not the major) component
* is interpreted as a compatible version change. The service
* level component is interpreted as a cumulative and compatible
* service update of the minor version component. The qualifier is
* not interpreted, other than in version comparisons. The
* qualifiers are compared using lexicographical string comparison.
* </p>
* <p>
* Version identifiers can be matched as perfectly equal, equivalent,
* compatible or greaterOrEqual.
* </p><p>
* This class can be used without OSGi running.
* </p><p>
* Clients may instantiate; not intended to be subclassed by clients.
* </p>
* @see java.lang.String#compareTo(java.lang.String)
* @deprecated clients should use {@link org.osgi.framework.Version} instead
*/
@Deprecated
public final class PluginVersionIdentifier {
private Version version;
private static final String SEPARATOR = "."; //$NON-NLS-1$
/**
* Creates a plug-in version identifier from its components.
*
* @param major major component of the version identifier
* @param minor minor component of the version identifier
* @param service service update component of the version identifier
*/
public PluginVersionIdentifier(int major, int minor, int service) {
this(major, minor, service, null);
}
/**
* Creates a plug-in version identifier from its components.
*
* @param major major component of the version identifier
* @param minor minor component of the version identifier
* @param service service update component of the version identifier
* @param qualifier qualifier component of the version identifier.
* Qualifier characters that are not a letter or a digit are replaced.
*/
public PluginVersionIdentifier(int major, int minor, int service, String qualifier) {
// Do the test outside of the assert so that they 'Policy.bind'
// will not be evaluated each time (including cases when we would
// have passed by the assert).
if (major < 0)
Assert.isTrue(false, NLS.bind(CommonMessages.parse_postiveMajor, major + SEPARATOR + minor + SEPARATOR + service + SEPARATOR + qualifier));
if (minor < 0)
Assert.isTrue(false, NLS.bind(CommonMessages.parse_postiveMinor, major + SEPARATOR + minor + SEPARATOR + service + SEPARATOR + qualifier));
if (service < 0)
Assert.isTrue(false, NLS.bind(CommonMessages.parse_postiveService, major + SEPARATOR + minor + SEPARATOR + service + SEPARATOR + qualifier));
this.version = new Version(major, minor, service, qualifier);
}
/**
* Creates a plug-in version identifier from the given string.
* The string representation consists of up to 4 tokens
* separated by decimal point.
* For example, the following are valid version identifiers
* (as strings):
* <ul>
* <li><code>0.0.0</code></li>
* <li><code>1.0.127564</code></li>
* <li><code>3.7.2.build-127J</code></li>
* <li><code>1.9</code> (interpreted as <code>1.9.0</code>)</li>
* <li><code>3</code> (interpreted as <code>3.0.0</code>)</li>
* </ul>
* </p>
*
* @param versionId string representation of the version identifier.
* Qualifier characters that are not a letter or a digit are replaced.
*/
public PluginVersionIdentifier(String versionId) {
Object[] parts = parseVersion(versionId);
version = new Version(((Integer) parts[0]).intValue(), ((Integer) parts[1]).intValue(), ((Integer) parts[2]).intValue(), (String) parts[3]);
}
/**
* Validates the given string as a plug-in version identifier.
*
* @param version the string to validate
* @return a status object with code <code>IStatus.OK</code> if
* the given string is valid as a plug-in version identifier, otherwise a status
* object indicating what is wrong with the string
* @since 2.0
*/
public static IStatus validateVersion(String version) {
try {
parseVersion(version);
} catch (RuntimeException e) {
return new Status(IStatus.ERROR, IRuntimeConstants.PI_RUNTIME, IStatus.ERROR, e.getMessage(), e);
}
return Status.OK_STATUS;
}
private static Object[] parseVersion(String versionId) {
// Do the test outside of the assert so that they 'Policy.bind'
// will not be evaluated each time (including cases when we would
// have passed by the assert).
if (versionId == null)
Assert.isNotNull(null, CommonMessages.parse_emptyPluginVersion);
String s = versionId.trim();
if (s.equals("")) //$NON-NLS-1$
Assert.isTrue(false, CommonMessages.parse_emptyPluginVersion);
if (s.startsWith(SEPARATOR))
Assert.isTrue(false, NLS.bind(CommonMessages.parse_separatorStartVersion, s));
if (s.endsWith(SEPARATOR))
Assert.isTrue(false, NLS.bind(CommonMessages.parse_separatorEndVersion, s));
if (s.indexOf(SEPARATOR + SEPARATOR) != -1)
Assert.isTrue(false, NLS.bind(CommonMessages.parse_doubleSeparatorVersion, s));
StringTokenizer st = new StringTokenizer(s, SEPARATOR);
Vector<String> elements = new Vector<>(4);
while (st.hasMoreTokens())
elements.addElement(st.nextToken());
int elementSize = elements.size();
if (elementSize <= 0)
Assert.isTrue(false, NLS.bind(CommonMessages.parse_oneElementPluginVersion, s));
if (elementSize > 4)
Assert.isTrue(false, NLS.bind(CommonMessages.parse_fourElementPluginVersion, s));
int[] numbers = new int[3];
try {
numbers[0] = Integer.parseInt(elements.elementAt(0));
if (numbers[0] < 0)
Assert.isTrue(false, NLS.bind(CommonMessages.parse_postiveMajor, s));
} catch (NumberFormatException nfe) {
Assert.isTrue(false, NLS.bind(CommonMessages.parse_numericMajorComponent, s));
}
try {
if (elementSize >= 2) {
numbers[1] = Integer.parseInt(elements.elementAt(1));
if (numbers[1] < 0)
Assert.isTrue(false, NLS.bind(CommonMessages.parse_postiveMinor, s));
} else
numbers[1] = 0;
} catch (NumberFormatException nfe) {
Assert.isTrue(false, NLS.bind(CommonMessages.parse_numericMinorComponent, s));
}
try {
if (elementSize >= 3) {
numbers[2] = Integer.parseInt(elements.elementAt(2));
if (numbers[2] < 0)
Assert.isTrue(false, NLS.bind(CommonMessages.parse_postiveService, s));
} else
numbers[2] = 0;
} catch (NumberFormatException nfe) {
Assert.isTrue(false, NLS.bind(CommonMessages.parse_numericServiceComponent, s));
}
// "result" is a 4-element array with the major, minor, service, and qualifier
Object[] result = new Object[4];
result[0] = new Integer(numbers[0]);
result[1] = new Integer(numbers[1]);
result[2] = new Integer(numbers[2]);
if (elementSize >= 4)
result[3] = elements.elementAt(3);
else
result[3] = ""; //$NON-NLS-1$
return result;
}
/**
* Compare version identifiers for equality. Identifiers are
* equal if all of their components are equal.
*
* @param object an object to compare
* @return whether or not the two objects are equal
*/
@Override
public boolean equals(Object object) {
if (!(object instanceof PluginVersionIdentifier))
return false;
PluginVersionIdentifier v = (PluginVersionIdentifier) object;
return version.equals(v.version);
}
/**
* Returns a hash code value for the object.
*
* @return an integer which is a hash code value for this object.
*/
@Override
public int hashCode() {
return version.hashCode();
}
/**
* Returns the major (incompatible) component of this
* version identifier.
*
* @return the major version
*/
public int getMajorComponent() {
return version.getMajor();
}
/**
* Returns the minor (compatible) component of this
* version identifier.
*
* @return the minor version
*/
public int getMinorComponent() {
return version.getMinor();
}
/**
* Returns the service level component of this
* version identifier.
*
* @return the service level
*/
public int getServiceComponent() {
return version.getMicro();
}
/**
* Returns the qualifier component of this
* version identifier.
*
* @return the qualifier
*/
public String getQualifierComponent() {
return version.getQualifier();
}
/**
* Compares two version identifiers to see if this one is
* greater than or equal to the argument.
* <p>
* A version identifier is considered to be greater than or equal
* if its major component is greater than the argument major
* component, or the major components are equal and its minor component
* is greater than the argument minor component, or the
* major and minor components are equal and its service component is
* greater than the argument service component, or the major, minor and
* service components are equal and the qualifier component is
* greater than the argument qualifier component (using lexicographic
* string comparison), or all components are equal.
* </p>
*
* @param id the other version identifier
* @return <code>true</code> is this version identifier
* is compatible with the given version identifier, and
* <code>false</code> otherwise
* @since 2.0
*/
public boolean isGreaterOrEqualTo(PluginVersionIdentifier id) {
if (id == null)
return false;
if (getMajorComponent() > id.getMajorComponent())
return true;
if ((getMajorComponent() == id.getMajorComponent()) && (getMinorComponent() > id.getMinorComponent()))
return true;
if ((getMajorComponent() == id.getMajorComponent()) && (getMinorComponent() == id.getMinorComponent()) && (getServiceComponent() > id.getServiceComponent()))
return true;
if ((getMajorComponent() == id.getMajorComponent()) && (getMinorComponent() == id.getMinorComponent()) && (getServiceComponent() == id.getServiceComponent()) && (getQualifierComponent().compareTo(id.getQualifierComponent()) >= 0))
return true;
return false;
}
/**
* Compares two version identifiers for compatibility.
* <p>
* A version identifier is considered to be compatible if its major
* component equals to the argument major component, and its minor component
* is greater than or equal to the argument minor component.
* If the minor components are equal, than the service level of the
* version identifier must be greater than or equal to the service level
* of the argument identifier. If the service levels are equal, the two
* version identifiers are considered to be equivalent if this qualifier is
* greater or equal to the qualifier of the argument (using lexicographic
* string comparison).
* </p>
*
* @param id the other version identifier
* @return <code>true</code> is this version identifier
* is compatible with the given version identifier, and
* <code>false</code> otherwise
*/
public boolean isCompatibleWith(PluginVersionIdentifier id) {
if (id == null)
return false;
if (getMajorComponent() != id.getMajorComponent())
return false;
if (getMinorComponent() > id.getMinorComponent())
return true;
if (getMinorComponent() < id.getMinorComponent())
return false;
if (getServiceComponent() > id.getServiceComponent())
return true;
if (getServiceComponent() < id.getServiceComponent())
return false;
if (getQualifierComponent().compareTo(id.getQualifierComponent()) >= 0)
return true;
return false;
}
/**
* Compares two version identifiers for equivalency.
* <p>
* Two version identifiers are considered to be equivalent if their major
* and minor component equal and are at least at the same service level
* as the argument. If the service levels are equal, the two version
* identifiers are considered to be equivalent if this qualifier is
* greater or equal to the qualifier of the argument (using lexicographic
* string comparison).
*
* </p>
*
* @param id the other version identifier
* @return <code>true</code> is this version identifier
* is equivalent to the given version identifier, and
* <code>false</code> otherwise
*/
public boolean isEquivalentTo(PluginVersionIdentifier id) {
if (id == null)
return false;
if (getMajorComponent() != id.getMajorComponent())
return false;
if (getMinorComponent() != id.getMinorComponent())
return false;
if (getServiceComponent() > id.getServiceComponent())
return true;
if (getServiceComponent() < id.getServiceComponent())
return false;
if (getQualifierComponent().compareTo(id.getQualifierComponent()) >= 0)
return true;
return false;
}
/**
* Compares two version identifiers for perfect equality.
* <p>
* Two version identifiers are considered to be perfectly equal if their
* major, minor, service and qualifier components are equal
* </p>
*
* @param id the other version identifier
* @return <code>true</code> is this version identifier
* is perfectly equal to the given version identifier, and
* <code>false</code> otherwise
* @since 2.0
*/
public boolean isPerfect(PluginVersionIdentifier id) {
if (id == null)
return false;
if ((getMajorComponent() != id.getMajorComponent()) || (getMinorComponent() != id.getMinorComponent()) || (getServiceComponent() != id.getServiceComponent()) || (!getQualifierComponent().equals(id.getQualifierComponent())))
return false;
return true;
}
/**
* Compares two version identifiers for order using multi-decimal
* comparison.
*
* @param id the other version identifier
* @return <code>true</code> is this version identifier
* is greater than the given version identifier, and
* <code>false</code> otherwise
*/
public boolean isGreaterThan(PluginVersionIdentifier id) {
if (id == null) {
if (getMajorComponent() == 0 && getMinorComponent() == 0 && getServiceComponent() == 0 && getQualifierComponent().equals("")) //$NON-NLS-1$
return false;
return true;
}
if (getMajorComponent() > id.getMajorComponent())
return true;
if (getMajorComponent() < id.getMajorComponent())
return false;
if (getMinorComponent() > id.getMinorComponent())
return true;
if (getMinorComponent() < id.getMinorComponent())
return false;
if (getServiceComponent() > id.getServiceComponent())
return true;
if (getServiceComponent() < id.getServiceComponent())
return false;
if (getQualifierComponent().compareTo(id.getQualifierComponent()) > 0)
return true;
return false;
}
/**
* Returns the string representation of this version identifier.
* The result satisfies
* <code>vi.equals(new PluginVersionIdentifier(vi.toString()))</code>.
*
* @return the string representation of this plug-in version identifier
*/
@Override
public String toString() {
return version.toString();
}
}