blob: 6221d67c1c272f7e4e64f0e874431b3ea233c749 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2018 IBM Corporation 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:
* IBM Corporation - initial API and implementation
* Compeople AG (Stefan Liebig) - various ongoing maintenance
* Mykola Nikishov - multiple artifact checksums
*******************************************************************************/
package org.eclipse.equinox.p2.repository.tools.comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.RegistryFactory;
import org.eclipse.equinox.internal.p2.artifact.processors.checksum.ChecksumUtilities;
import org.eclipse.equinox.internal.p2.artifact.repository.Messages;
import org.eclipse.equinox.p2.internal.repository.comparator.*;
import org.eclipse.osgi.util.NLS;
/**
* @since 2.0
*/
public class ArtifactComparatorFactory {
private static final String COMPARATOR_POINT = "org.eclipse.equinox.p2.artifact.repository.artifactComparators"; //$NON-NLS-1$
private static final String ATTR_ID = "id"; //$NON-NLS-1$
private static final String ATTR_CLASS = "class"; //$NON-NLS-1$
/**
* Find artifact comparator by comparator's extension id, for instance:
* <ul>
* <li><code>org.eclipse.equinox.p2.repository.tools.jar.comparator</code> for {@link JarComparator}</li>
* <li><code>org.eclipse.equinox.artifact.md5.comparator</code> for {@link MD5ArtifactComparator}</li>
* </ul>
*
* For {@link ArtifactChecksumComparator}, there is no static id that could be used directly. Instead, its extension point id <code>org.eclipse.equinox.artifact.comparator.checksum</code> should be concatenated with id of desired checksum algorithm:
* <ul>
* <li><code>org.eclipse.equinox.artifact.comparator.checksum.sha-256</code> to use artifact checksum comparator with SHA-256 message digest</li>
* <li><code>org.eclipse.equinox.artifact.comparator.checksum.tiger</code> to use Tiger message digest</li>
* </ul>
*
* @param comparatorID id of the extension contributed to <code>org.eclipse.equinox.p2.artifact.repository.artifactComparators</code> extension point
* @return if found, instance of artifact comparator
* @throws {@link IllegalArgumentException} otherwise
*/
public static IArtifactComparator getArtifactComparator(String comparatorID) {
List<IConfigurationElement> extensions = Stream.of(RegistryFactory.getRegistry().getConfigurationElementsFor(COMPARATOR_POINT))
.collect(Collectors.toList());
// exclude artifact checksum comparator, needs special care
extensions.removeIf(extension -> extension.getAttribute(ATTR_ID).equals(ArtifactChecksumComparator.COMPARATOR_ID));
// handle generic artifact comparators
Optional<IArtifactComparator> artifactComparator = findComparatorConfiguration(comparatorID, extensions)
.map(ArtifactComparatorFactory::createArtifactComparator);
if (artifactComparator.isPresent())
return artifactComparator.get();
// handle artifact checksum comparator
if (comparatorID != null && comparatorID.startsWith(ArtifactChecksumComparator.COMPARATOR_ID)) {
Optional<ArtifactChecksumComparator> checksumComparator = getChecksumComparator(comparatorID);
if (checksumComparator.isPresent())
return checksumComparator.get();
}
if (comparatorID != null) {
Stream<String> checksumComparators = Stream.of(ChecksumUtilities.getChecksumComparatorConfigurations())
.map(element -> element.getAttribute(CHECKSUM_ID))
.map(checksumId -> ArtifactChecksumComparator.COMPARATOR_ID.concat(".").concat(checksumId)); //$NON-NLS-1$
Stream<String> comparators = extensions.stream()
.map(extension -> extension.getAttribute(ATTR_ID));
String availableComparators = Stream.concat(comparators, checksumComparators).collect(Collectors.joining(", ")); //$NON-NLS-1$
throw new IllegalArgumentException(NLS.bind(Messages.exception_comparatorNotFound, comparatorID, availableComparators));
}
throw new IllegalArgumentException(Messages.exception_noComparators);
}
private static Optional<IConfigurationElement> findComparatorConfiguration(String comparatorID, List<IConfigurationElement> extensions) {
if (comparatorID == null && extensions.size() > 0) {
return Optional.ofNullable(extensions.get(0)); //just take the first one
}
return extensions.stream().filter(extension -> extension.getAttribute(ATTR_ID).equals(comparatorID)).findAny();
}
private static IArtifactComparator createArtifactComparator(IConfigurationElement element) {
try {
Object execExt = element.createExecutableExtension(ATTR_CLASS);
if (execExt instanceof IArtifactComparator)
return (IArtifactComparator) execExt;
} catch (Exception e) {
//fall through
}
return null;
}
private static final String CHECKSUM_ID = "id"; //$NON-NLS-1$
private static final String CHECKSUM_ALGORITHM = "algorithm"; //$NON-NLS-1$
private static Optional<ArtifactChecksumComparator> getChecksumComparator(String comparatorId) {
boolean hasNoChecksumId = !comparatorId.startsWith(ArtifactChecksumComparator.COMPARATOR_ID.concat(".")); //$NON-NLS-1$
if (hasNoChecksumId)
return Optional.empty();
String comparatorChecksum = Optional.ofNullable(comparatorId.substring(ArtifactChecksumComparator.COMPARATOR_ID.length() + 1))
.orElse(""); //$NON-NLS-1$
if (comparatorChecksum.isEmpty())
return Optional.empty();
IConfigurationElement[] comparatorConfigurations = ChecksumUtilities.getChecksumComparatorConfigurations();
Optional<IConfigurationElement> comparator = Stream.of(comparatorConfigurations)
.filter(config -> config.getAttribute(CHECKSUM_ID).equals(comparatorChecksum))
.findAny();
return comparator.map(c -> {
String checksumName = c.getAttribute(CHECKSUM_ALGORITHM);
String checksumId = c.getAttribute(CHECKSUM_ID);
return Optional.of(new ArtifactChecksumComparator(checksumId, checksumName));
}).orElse(Optional.empty());
}
}