/******************************************************************************* * Copyright (c) 2007, 2010 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 *******************************************************************************/ package org.eclipse.equinox.p2.operations; import java.io.File; import java.net.URI; import java.net.URISyntaxException; import java.util.*; import org.eclipse.core.runtime.*; import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; import org.eclipse.equinox.internal.p2.operations.*; import org.eclipse.equinox.internal.p2.repository.helpers.RepositoryHelper; import org.eclipse.equinox.p2.core.ProvisionException; import org.eclipse.equinox.p2.repository.IRepositoryManager; import org.eclipse.osgi.util.NLS; /** * RepositoryTracker defines a service that retrieves repositories, tracks their status, and * reports errors. * * @since 2.0 */ public abstract class RepositoryTracker { /** * A status code used to indicate that a repository location was not valid. */ public static final int STATUS_INVALID_REPOSITORY_LOCATION = IStatusCodes.INVALID_REPOSITORY_LOCATION; // What repositories to show private int artifactRepositoryFlags = IRepositoryManager.REPOSITORIES_NON_SYSTEM; private int metadataRepositoryFlags = IRepositoryManager.REPOSITORIES_NON_SYSTEM; /** * List<URI> of repositories that have already been reported to the user as not found. */ private final List<URI> reposNotFound = Collections.synchronizedList(new ArrayList<URI>()); /** * Return an array of repository locations known for the specified provisioning session. * * @param session the provisioning session providing the provisioning services * @return an array of repository locations known by this tracker */ public abstract URI[] getKnownRepositories(ProvisioningSession session); /** * Return a status appropriate for reporting an invalid repository location. * @param locationText the text representation of the location * @return a status that describes an invalid location */ public IStatus getInvalidLocationStatus(String locationText) { return new Status(IStatus.ERROR, Activator.ID, IStatusCodes.INVALID_REPOSITORY_LOCATION, NLS.bind(Messages.RepositoryTracker_InvalidLocation, locationText), null); } /** * Return a repository location represented by the supplied string. The provided * string should either be an unencoded string representation of a URI, or a * local file system path. This method is generally suitable for converting a * location string entered by an end user into a suitable URI representation. * * @param locationString a text representation of the location * @return a repository location URI, or <code>null</code> if the * text could not be interpreted. */ public URI locationFromString(String locationString) { URI userLocation; try { userLocation = URIUtil.fromString(locationString); } catch (URISyntaxException e) { return null; } // If a path separator char was used, interpret as a local file URI String uriString = URIUtil.toUnencodedString(userLocation); if (uriString.length() > 0 && (uriString.charAt(0) == '/' || uriString.charAt(0) == File.separatorChar)) return RepositoryHelper.localRepoURIHelper(userLocation); return userLocation; } /** * Validate the specified repository location. * * @param session the provisioning session providing the repository services * @param location the location in question * @param contactRepositories <code>true</code> if the appropriate repository manager(s) should be * consulted regarding the validity of the location, or <code>false</code> if the repository manager * should not be consulted. * @param monitor the progress monitor * @return a status indicating the current status of the repository */ public IStatus validateRepositoryLocation(ProvisioningSession session, URI location, boolean contactRepositories, IProgressMonitor monitor) { // First validate syntax issues IStatus localValidationStatus = RepositoryHelper.checkRepositoryLocationSyntax(location); if (!localValidationStatus.isOK()) { // bad syntax, but it could just be non-absolute. // In this case, use the helper String locationString = URIUtil.toUnencodedString(location); if (locationString.length() > 0 && (locationString.charAt(0) == '/' || locationString.charAt(0) == File.separatorChar)) { location = RepositoryHelper.localRepoURIHelper(location); localValidationStatus = RepositoryHelper.checkRepositoryLocationSyntax(location); } } if (!localValidationStatus.isOK()) return localValidationStatus; if (contains(location, session)) return new Status(IStatus.ERROR, Activator.ID, IStatusCodes.INVALID_REPOSITORY_LOCATION, Messages.RepositoryTracker_DuplicateLocation, null); return Status.OK_STATUS; } /** * Return a boolean indicating whether this tracker already contains the specified * repository location. * * @param location the location in question * @param session the provisioning session providing the repository services * @since 2.1 */ protected boolean contains(URI location, ProvisioningSession session) { // This is a fallback implementation in the absence of a repository manager // that would know what to do. URI[] knownRepositories = getKnownRepositories(session); for (int i = 0; i < knownRepositories.length; i++) { if (URIUtil.sameURI(knownRepositories[i], location)) { return true; } } return false; } /** * Add the specified location to the list of "not found" repositories. * This list is used to ensure that errors are not reported multiple times * for the same repository. * * The caller is already assumed to have reported any errors if necessary. * * @param location the location of the repository that cannot be found */ public void addNotFound(URI location) { reposNotFound.add(location); } /** * Answer a boolean indicating whether not found status has already been * reported for the specified location. * * @param location the location in question * @return <code>true</code> if the repository has already been reported as * being not found, <code>false</code> if no status has been reported for this * location. */ public boolean hasNotFoundStatusBeenReported(URI location) { // We don't check for things like case variants or end slash variants // because we know that the repository managers already did this. return reposNotFound.contains(location); } /** * Clear the list of repositories that have already been reported as not found. */ public void clearRepositoriesNotFound() { reposNotFound.clear(); } /** * Remove the specified repository from the list of repositories that * have already been reported as not found. This method has no effect * if the repository has never been reported as not found. * * @param location the location in question */ public void clearRepositoryNotFound(URI location) { reposNotFound.remove(location); } /** * Return the repository flags suitable for retrieving known repositories from * a repository manager * * @return the repository flags * */ public int getArtifactRepositoryFlags() { return artifactRepositoryFlags; } /** * Set the repository flags suitable for retrieving known repositories from * a repository manager * * @param flags the repository flags * */ public void setArtifactRepositoryFlags(int flags) { artifactRepositoryFlags = flags; } /** * Return the repository flags suitable for retrieving known repositories from * a repository manager * * @return the repository flags * */ public int getMetadataRepositoryFlags() { return metadataRepositoryFlags; } /** * Set the repository flags suitable for retrieving known repositories from * a repository manager * * @param flags the repository flags * */ public void setMetadataRepositoryFlags(int flags) { metadataRepositoryFlags = flags; } /** * Report a failure to load the specified repository. * <p> * This default implementation simply logs the failure. Subclasses may override * to provide additional error reporting. * </p> * @param location the location of the failed repository * @param exception the failure that occurred */ public void reportLoadFailure(final URI location, ProvisionException exception) { // special handling when the repo location is bad. We don't want to continually report it int code = exception.getStatus().getCode(); if (code == IStatusCodes.INVALID_REPOSITORY_LOCATION || code == ProvisionException.REPOSITORY_INVALID_LOCATION || code == ProvisionException.REPOSITORY_NOT_FOUND) { if (hasNotFoundStatusBeenReported(location)) return; addNotFound(location); } LogHelper.log(exception.getStatus()); } /** * Add a repository at the specified location. * * @param location the location of the new repository * @param nickname the nickname for the repository, or <code>null</code> if there is no nickname * @param session the session to use for provisioning services */ public abstract void addRepository(URI location, String nickname, ProvisioningSession session); /** * Remove the repositories at the specified locations * * @param locations the locations * @param session the session to use for provisioning services */ public abstract void removeRepositories(URI[] locations, ProvisioningSession session); /** * Refresh the repositories at the specified locations * @param locations the locations * @param session the session to use for provisioning services * @param monitor the progress monitor to use */ public abstract void refreshRepositories(URI[] locations, ProvisioningSession session, IProgressMonitor monitor); }