| /******************************************************************************* |
| * Copyright (c) 2007, 2009 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 |
| * Compeople AG (Stefan Liebig) - various ongoing maintenance |
| *******************************************************************************/ |
| package org.eclipse.equinox.internal.p2.artifact.mirror; |
| |
| import org.eclipse.equinox.p2.metadata.IArtifactKey; |
| |
| import java.util.*; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.equinox.internal.p2.artifact.repository.*; |
| import org.eclipse.equinox.internal.provisional.p2.artifact.repository.ArtifactComparatorFactory; |
| import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactComparator; |
| import org.eclipse.equinox.internal.provisional.p2.core.ProvisionException; |
| import org.eclipse.equinox.internal.provisional.p2.metadata.query.Collector; |
| import org.eclipse.equinox.p2.repository.artifact.*; |
| import org.eclipse.equinox.p2.repository.artifact.spi.ArtifactDescriptor; |
| import org.eclipse.osgi.util.NLS; |
| |
| /** |
| * A utility class that performs mirroring of artifacts between repositories. |
| */ |
| public class Mirroring { |
| private IArtifactRepository source; |
| private IArtifactRepository destination; |
| private IArtifactRepository baseline; |
| private boolean raw; |
| private boolean compare = false; |
| private boolean validate = false; |
| private IArtifactComparator comparator; |
| private String comparatorID; |
| private List keysToMirror; |
| private IArtifactMirrorLog comparatorLog; |
| |
| private IArtifactComparator getComparator() { |
| if (comparator == null) |
| comparator = ArtifactComparatorFactory.getArtifactComparator(comparatorID); |
| return comparator; |
| } |
| |
| public Mirroring(IArtifactRepository source, IArtifactRepository destination, boolean raw) { |
| this.source = source; |
| this.destination = destination; |
| this.raw = raw; |
| } |
| |
| public void setCompare(boolean compare) { |
| this.compare = compare; |
| } |
| |
| public void setComparatorId(String id) { |
| this.comparatorID = id; |
| } |
| |
| public void setComparatorLog(IArtifactMirrorLog comparatorLog) { |
| this.comparatorLog = comparatorLog; |
| } |
| |
| public void setBaseline(IArtifactRepository baseline) { |
| this.baseline = baseline; |
| } |
| |
| public void setValidate(boolean validate) { |
| this.validate = validate; |
| } |
| |
| public MultiStatus run(boolean failOnError, boolean verbose) { |
| if (!destination.isModifiable()) |
| throw new IllegalStateException(NLS.bind(Messages.exception_destinationNotModifiable, destination.getLocation())); |
| if (compare) |
| getComparator(); //initialize the comparator. Only needed if we're comparing. Used to force error if comparatorID is invalid. |
| MultiStatus multiStatus = new MultiStatus(Activator.ID, IStatus.OK, Messages.message_mirroringStatus, null); |
| Iterator keys = null; |
| if (keysToMirror != null) |
| keys = keysToMirror.iterator(); |
| else { |
| Collector result = source.query(ArtifactKeyQuery.ALL_KEYS, new Collector(), null); |
| keys = result.iterator(); |
| } |
| while (keys.hasNext()) { |
| IArtifactKey key = (IArtifactKey) keys.next(); |
| IArtifactDescriptor[] descriptors = source.getArtifactDescriptors(key); |
| for (int j = 0; j < descriptors.length; j++) { |
| IStatus result = mirror(descriptors[j], verbose); |
| //Only log INFO and WARNING if we want verbose logging. Always log ERRORs |
| if (!result.isOK() && (verbose || result.getSeverity() == IStatus.ERROR)) |
| multiStatus.add(result); |
| //stop mirroring as soon as we have an error |
| if (failOnError && multiStatus.getSeverity() == IStatus.ERROR) |
| return multiStatus; |
| } |
| } |
| if (validate) { |
| // Simple validation of the mirror |
| IStatus validation = validateMirror(verbose); |
| if (!validation.isOK() && (verbose || validation.getSeverity() == IStatus.ERROR)) |
| multiStatus.add(validation); |
| } |
| return multiStatus; |
| } |
| |
| private IStatus mirror(IArtifactDescriptor descriptor, boolean verbose) { |
| IArtifactDescriptor newDescriptor = raw ? descriptor : new ArtifactDescriptor(descriptor); |
| |
| if (verbose) |
| System.out.println("Mirroring: " + descriptor.getArtifactKey() + " (Descriptor: " + descriptor + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| |
| if (compare && baseline != null) |
| if (baseline.contains(descriptor)) { |
| // we have to create an output stream based on the descriptor found in the baseline otherwise all |
| // the properties will be copied over from the wrong descriptor and our repository will be inconsistent. |
| IArtifactDescriptor baselineDescriptor = getBaselineDescriptor(descriptor); |
| |
| // if we found a descriptor in the baseline then we'll use it to copy the artifact |
| if (baselineDescriptor != null) { |
| MultiStatus status = new MultiStatus(Activator.ID, IStatus.OK, NLS.bind(Messages.Mirroring_compareAndDownload, descriptor), null); |
| //Compare source against baseline |
| IStatus comparison = getComparator().compare(baseline, baselineDescriptor, source, descriptor); |
| if (comparatorLog != null) |
| comparatorLog.log(baselineDescriptor, comparison); |
| status.add(comparison); |
| if (destination.contains(baselineDescriptor)) |
| return compareToDestination(baselineDescriptor); |
| |
| //download artifact from baseline |
| status.add(downloadArtifact(baseline, baselineDescriptor, baselineDescriptor)); |
| return status; |
| } |
| } |
| |
| // Check if the destination already contains the file. |
| if (destination.contains(newDescriptor)) { |
| if (compare) |
| return compareToDestination(descriptor); |
| String message = NLS.bind(Messages.mirror_alreadyExists, descriptor, destination); |
| return new Status(IStatus.INFO, Activator.ID, ProvisionException.ARTIFACT_EXISTS, message, null); |
| } |
| |
| return downloadArtifact(source, newDescriptor, descriptor); |
| } |
| |
| /** |
| * Takes an IArtifactDescriptor descriptor and the ProvisionException that was thrown when destination.getOutputStream(descriptor) |
| * and compares descriptor to the duplicate descriptor in the destination. |
| * |
| * Callers should verify the ProvisionException was thrown due to the artifact existing in the destination before invoking this method. |
| * @param descriptor |
| * @return the status of the compare |
| */ |
| private IStatus compareToDestination(IArtifactDescriptor descriptor) { |
| IArtifactDescriptor[] destDescriptors = destination.getArtifactDescriptors(descriptor.getArtifactKey()); |
| IArtifactDescriptor destDescriptor = null; |
| for (int i = 0; destDescriptor == null && i < destDescriptors.length; i++) { |
| if (destDescriptors[i].equals(descriptor)) |
| destDescriptor = destDescriptors[i]; |
| } |
| if (destDescriptor == null) |
| return new Status(IStatus.INFO, Activator.ID, ProvisionException.ARTIFACT_EXISTS, Messages.Mirroring_NO_MATCHING_DESCRIPTOR, null); |
| return compare(source, descriptor, destination, destDescriptor); |
| } |
| |
| private IStatus compare(IArtifactRepository sourceRepository, IArtifactDescriptor sourceDescriptor, IArtifactRepository destRepository, IArtifactDescriptor destDescriptor) { |
| IStatus comparison = getComparator().compare(sourceRepository, sourceDescriptor, destRepository, destDescriptor); |
| if (comparatorLog != null) |
| comparatorLog.log(sourceDescriptor, comparison); |
| return comparison; |
| } |
| |
| /* |
| * Create, and execute a MirrorRequest for a given descriptor. |
| */ |
| private IStatus downloadArtifact(IArtifactRepository sourceRepo, IArtifactDescriptor destDescriptor, IArtifactDescriptor srcDescriptor) { |
| RawMirrorRequest request = new RawMirrorRequest(srcDescriptor, destDescriptor, destination); |
| request.setSourceRepository(sourceRepo); |
| |
| request.perform(new NullProgressMonitor()); |
| |
| return request.getResult(); |
| } |
| |
| public void setArtifactKeys(IArtifactKey[] keys) { |
| this.keysToMirror = Arrays.asList(keys); |
| } |
| |
| /* |
| * Get the equivalent descriptor from the baseline repository |
| */ |
| private IArtifactDescriptor getBaselineDescriptor(IArtifactDescriptor descriptor) { |
| IArtifactDescriptor[] baselineDescriptors = baseline.getArtifactDescriptors(descriptor.getArtifactKey()); |
| for (int i = 0; i < baselineDescriptors.length; i++) { |
| if (baselineDescriptors[i].equals(descriptor)) |
| return baselineDescriptors[i]; |
| } |
| return null; |
| } |
| |
| /* |
| * Simple validation of a mirror to see if all source descriptors are present in the destination |
| */ |
| private IStatus validateMirror(boolean verbose) { |
| MultiStatus status = new MultiStatus(Activator.ID, 0, Messages.Mirroring_ValidationError, null); |
| |
| // The keys that were mirrored in this session |
| Iterator keys = null; |
| if (keysToMirror != null) { |
| keys = keysToMirror.iterator(); |
| } else { |
| Collector result = source.query(ArtifactKeyQuery.ALL_KEYS, new Collector(), null); |
| keys = result.iterator(); |
| } |
| while (keys.hasNext()) { |
| IArtifactKey artifactKey = (IArtifactKey) keys.next(); |
| IArtifactDescriptor[] srcDescriptors = source.getArtifactDescriptors(artifactKey); |
| IArtifactDescriptor[] destDescriptors = destination.getArtifactDescriptors(artifactKey); |
| |
| Arrays.sort(srcDescriptors, new ArtifactDescriptorComparator()); |
| Arrays.sort(destDescriptors, new ArtifactDescriptorComparator()); |
| |
| int src = 0; |
| int dest = 0; |
| while (src < srcDescriptors.length && dest < destDescriptors.length) { |
| if (!destDescriptors[dest].equals(srcDescriptors[src])) { |
| if (destDescriptors[dest].toString().compareTo((srcDescriptors[src].toString())) > 0) { |
| // Missing an artifact |
| if (verbose) |
| System.out.println(NLS.bind(Messages.Mirroring_MISSING_DESCRIPTOR, srcDescriptors[src])); |
| status.add(new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Mirroring_MISSING_DESCRIPTOR, srcDescriptors[src++]))); |
| } else { |
| // Its okay if there are extra descriptors in the destination |
| dest++; |
| } |
| } else { |
| // check properties for differences |
| Map destMap = destDescriptors[dest].getProperties(); |
| Map srcProperties = null; |
| if (baseline != null) { |
| IArtifactDescriptor baselineDescriptor = getBaselineDescriptor(destDescriptors[dest]); |
| if (baselineDescriptor != null) |
| srcProperties = baselineDescriptor.getProperties(); |
| } |
| // Baseline not set, or could not find descriptor so we'll use the source descriptor |
| if (srcProperties == null) |
| srcProperties = srcDescriptors[src].getProperties(); |
| |
| // Cycle through properties of the originating descriptor & compare |
| for (Iterator iter = srcProperties.keySet().iterator(); iter.hasNext();) { |
| String key = (String) iter.next(); |
| if (!srcProperties.get(key).equals(destMap.get(key))) { |
| if (verbose) |
| System.out.println(NLS.bind(Messages.Mirroring_DIFFERENT_DESCRIPTOR_PROPERTY, new Object[] {destDescriptors[dest], key, srcProperties.get(key), destMap.get(key)})); |
| status.add(new Status(IStatus.WARNING, Activator.ID, NLS.bind(Messages.Mirroring_DIFFERENT_DESCRIPTOR_PROPERTY, new Object[] {destDescriptors[dest], key, srcProperties.get(key), destMap.get(key)}))); |
| } |
| } |
| src++; |
| dest++; |
| } |
| } |
| |
| // If there are still source descriptors they're missing from the destination repository |
| while (src < srcDescriptors.length) { |
| if (verbose) |
| System.out.println(NLS.bind(Messages.Mirroring_MISSING_DESCRIPTOR, srcDescriptors[src])); |
| status.add(new Status(IStatus.ERROR, Activator.ID, NLS.bind(Messages.Mirroring_MISSING_DESCRIPTOR, srcDescriptors[src++]))); |
| } |
| } |
| |
| return status; |
| } |
| |
| // Simple comparator for ArtifactDescriptors |
| protected class ArtifactDescriptorComparator implements Comparator { |
| |
| public int compare(Object arg0, Object arg1) { |
| if (arg0 != null && arg1 != null) |
| return arg0.toString().compareTo(arg1.toString()); |
| else if (arg1 == null && arg0 == null) |
| return 0; |
| else if (arg1 == null) |
| return 1; |
| return -1; |
| } |
| } |
| } |