blob: ff8b9b25332a2dbc20389838e6367cde3c3ab264 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 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
* Ray Braithwood (ray@genuitec.com) - fix for bug 220605
*******************************************************************************/
package org.eclipse.equinox.internal.p2.updatesite.metadata;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.core.helpers.LogHelper;
import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper;
import org.eclipse.equinox.internal.p2.metadata.generator.features.*;
import org.eclipse.equinox.internal.p2.updatesite.*;
import org.eclipse.equinox.internal.p2.updatesite.Messages;
import org.eclipse.equinox.internal.provisional.p2.core.ProvisionException;
import org.eclipse.equinox.internal.provisional.p2.core.eventbus.IProvisioningEventBus;
import org.eclipse.equinox.internal.provisional.p2.core.repository.IRepository;
import org.eclipse.equinox.internal.provisional.p2.core.repository.RepositoryEvent;
import org.eclipse.equinox.internal.provisional.p2.metadata.IArtifactKey;
import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.internal.provisional.p2.metadata.generator.*;
import org.eclipse.equinox.internal.provisional.p2.metadata.repository.IMetadataRepository;
import org.eclipse.equinox.internal.provisional.p2.query.Collector;
import org.eclipse.equinox.internal.provisional.p2.query.Query;
import org.eclipse.equinox.internal.provisional.spi.p2.metadata.repository.AbstractMetadataRepository;
import org.eclipse.equinox.internal.provisional.spi.p2.metadata.repository.SimpleMetadataRepositoryFactory;
import org.eclipse.osgi.service.resolver.*;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
public class UpdateSiteMetadataRepository extends AbstractMetadataRepository {
public static final String TYPE = "org.eclipse.equinox.p2.updatesite.metadataRepository"; //$NON-NLS-1$
public static final Integer VERSION = new Integer(1);
private final IMetadataRepository metadataRepository;
private static final String FEATURE_VERSION_SEPARATOR = "_"; //$NON-NLS-1$
private static final String PROP_SITE_CHECKSUM = "site.checksum"; //$NON-NLS-1$
public UpdateSiteMetadataRepository(URL location, IProgressMonitor monitor) throws ProvisionException {
super(Activator.getRepositoryName(location), TYPE, VERSION.toString(), location, null, null, null);
// todo progress monitoring
// loading validates before we create repositories
UpdateSite updateSite = UpdateSite.load(location, null);
broadcastAssociateSites(updateSite);
BundleContext context = Activator.getBundleContext();
String stateDirName = Integer.toString(location.toExternalForm().hashCode());
File bundleData = context.getDataFile(null);
File stateDir = new File(bundleData, stateDirName);
URL localRepositoryURL;
try {
localRepositoryURL = stateDir.toURL();
} catch (MalformedURLException e) {
// unexpected
throw new ProvisionException(new Status(IStatus.ERROR, Activator.ID, Messages.ErrorCreatingRepository, e));
}
metadataRepository = initializeMetadataRepository(context, localRepositoryURL, "update site implementation - " + location.toExternalForm(), updateSite); //$NON-NLS-1$
String savedChecksum = (String) metadataRepository.getProperties().get(PROP_SITE_CHECKSUM);
if (savedChecksum != null && savedChecksum.equals(updateSite.getChecksum()))
return;
metadataRepository.removeAll();
generateMetadata(updateSite);
metadataRepository.setProperty(PROP_SITE_CHECKSUM, updateSite.getChecksum());
}
/**
* Broadcast events for any associated sites for this repository so repository
* managers are aware of them.
*/
private void broadcastAssociateSites(UpdateSite baseSite) {
if (baseSite == null)
return;
URLEntry[] sites = baseSite.getSite().getAssociatedSites();
if (sites == null || sites.length == 0)
return;
IProvisioningEventBus bus = (IProvisioningEventBus) ServiceHelper.getService(Activator.getBundleContext(), IProvisioningEventBus.SERVICE_NAME);
if (bus == null)
return;
for (int i = 0; i < sites.length; i++) {
try {
URL siteLocation = new URL(sites[i].getURL());
bus.publishEvent(new RepositoryEvent(siteLocation, IRepository.TYPE_METADATA, RepositoryEvent.DISCOVERED, true));
bus.publishEvent(new RepositoryEvent(siteLocation, IRepository.TYPE_ARTIFACT, RepositoryEvent.DISCOVERED, true));
} catch (MalformedURLException e) {
LogHelper.log(new Status(IStatus.WARNING, Activator.ID, "Site has invalid associate site: " + baseSite.getLocation(), e)); //$NON-NLS-1$
}
}
}
private void generateMetadata(UpdateSite updateSite) throws ProvisionException {
SiteModel siteModel = updateSite.getSite();
// we load the features here to ensure that all site features are fully populated with
// id and version information before looking at category information
Feature[] features = updateSite.loadFeatures();
SiteCategory[] siteCategories = siteModel.getCategories();
Map categoryNameToFeatureIUs = new HashMap();
for (int i = 0; i < siteCategories.length; i++)
categoryNameToFeatureIUs.put(siteCategories[i].getName(), new HashSet());
SiteFeature[] siteFeatures = siteModel.getFeatures();
Map featureKeyToCategoryNames = new HashMap();
for (int i = 0; i < siteFeatures.length; i++) {
SiteFeature siteFeature = siteFeatures[i];
String featureKey = siteFeature.getFeatureIdentifier() + FEATURE_VERSION_SEPARATOR + siteFeature.getFeatureVersion();
featureKeyToCategoryNames.put(featureKey, siteFeature.getCategoryNames());
}
Properties extraProperties = new Properties();
extraProperties.put(IInstallableUnit.PROP_PARTIAL_IU, Boolean.TRUE.toString());
Set allSiteIUs = new HashSet();
BundleDescriptionFactory bundleDesciptionFactory = initializeBundleDescriptionFactory(Activator.getBundleContext());
for (int i = 0; i < features.length; i++) {
Feature feature = features[i];
FeatureEntry[] featureEntries = feature.getEntries();
for (int j = 0; j < featureEntries.length; j++) {
FeatureEntry entry = featureEntries[j];
if (entry.isPlugin() && !entry.isRequires()) {
Dictionary mockManifest = new Properties();
mockManifest.put("Manifest-Version", "1.0"); //$NON-NLS-1$ //$NON-NLS-2$
mockManifest.put("Bundle-ManifestVersion", "2"); //$NON-NLS-1$ //$NON-NLS-2$
mockManifest.put("Bundle-SymbolicName", entry.getId()); //$NON-NLS-1$
mockManifest.put("Bundle-Version", entry.getVersion()); //$NON-NLS-1$
BundleDescription bundleDescription = bundleDesciptionFactory.getBundleDescription(mockManifest, null);
IArtifactKey key = MetadataGeneratorHelper.createBundleArtifactKey(entry.getId(), entry.getVersion());
IInstallableUnit[] bundleIUs = MetadataGeneratorHelper.createEclipseIU(bundleDescription, null, entry.isUnpack(), key, extraProperties);
for (int n = 0; n < bundleIUs.length; n++) {
allSiteIUs.add(bundleIUs[n]);
}
}
}
IInstallableUnit featureIU = MetadataGeneratorHelper.createFeatureJarIU(feature, true);
IInstallableUnit groupIU = MetadataGeneratorHelper.createGroupIU(feature, featureIU);
String featureKey = feature.getId() + FEATURE_VERSION_SEPARATOR + feature.getVersion();
String[] categoryNames = (String[]) featureKeyToCategoryNames.get(featureKey);
if (categoryNames != null) {
for (int j = 0; j < categoryNames.length; j++) {
Set featureIUList = (Set) categoryNameToFeatureIUs.get(categoryNames[j]);
if (featureIUList != null) {
featureIUList.add(groupIU);
}
}
}
allSiteIUs.add(featureIU);
allSiteIUs.add(groupIU);
publishSites(feature);
}
for (int i = 0; i < siteCategories.length; i++) {
SiteCategory category = siteCategories[i];
Set featureIUs = (Set) categoryNameToFeatureIUs.get(category.getName());
IInstallableUnit categoryIU = MetadataGeneratorHelper.createCategoryIU(category, featureIUs, null);
allSiteIUs.add(categoryIU);
}
IInstallableUnit[] ius = (IInstallableUnit[]) allSiteIUs.toArray(new IInstallableUnit[allSiteIUs.size()]);
metadataRepository.addInstallableUnits(ius);
}
/*(non-Javadoc)
* @see IMetadataRepositoryFactory#validate(URL, IProgressMonitor)
*/
public static void validate(URL url, IProgressMonitor monitor) throws ProvisionException {
UpdateSite.validate(url, monitor);
}
private IMetadataRepository initializeMetadataRepository(BundleContext context, URL stateDirURL, String repositoryName, UpdateSite updateSite) {
SimpleMetadataRepositoryFactory factory = new SimpleMetadataRepositoryFactory();
try {
return factory.load(stateDirURL, null);
} catch (ProvisionException e) {
//fall through and create a new repository
}
Map props = new HashMap(5);
String mirrors = updateSite.getMirrorsURL();
if (mirrors != null) {
props.put(IRepository.PROP_MIRRORS_URL, mirrors);
//set the mirror base URL relative to the real remote repository rather than our local cache
props.put(IRepository.PROP_MIRRORS_BASE_URL, getLocation().toExternalForm());
}
return factory.create(stateDirURL, repositoryName, null, props);
}
private BundleDescriptionFactory initializeBundleDescriptionFactory(BundleContext context) {
ServiceReference reference = context.getServiceReference(PlatformAdmin.class.getName());
if (reference == null)
throw new IllegalStateException(Messages.PlatformAdminNotRegistered);
PlatformAdmin platformAdmin = (PlatformAdmin) context.getService(reference);
if (platformAdmin == null)
throw new IllegalStateException(Messages.PlatformAdminNotRegistered);
try {
StateObjectFactory stateObjectFactory = platformAdmin.getFactory();
return new BundleDescriptionFactory(stateObjectFactory, null);
} finally {
context.ungetService(reference);
}
}
public Map getProperties() {
return metadataRepository.getProperties();
}
public String setProperty(String key, String value) {
return metadataRepository.setProperty(key, value);
}
public Collector query(Query query, Collector collector, IProgressMonitor monitor) {
return metadataRepository.query(query, collector, monitor);
}
public void removeAll() {
metadataRepository.removeAll();
}
public void addInstallableUnits(IInstallableUnit[] installableUnits) {
metadataRepository.addInstallableUnits(installableUnits);
}
public boolean removeInstallableUnits(Query query, IProgressMonitor monitor) {
return metadataRepository.removeInstallableUnits(query, monitor);
}
public void initialize(RepositoryState state) {
//nothing to do
}
/**
* Broadcast events for any discovery sites associated with the feature
* so the repository managers add them to their list of known repositories.
*/
private void publishSites(Feature feature) {
IProvisioningEventBus bus = (IProvisioningEventBus) ServiceHelper.getService(Activator.getBundleContext(), IProvisioningEventBus.SERVICE_NAME);
if (bus == null)
return;
URLEntry[] discoverySites = feature.getDiscoverySites();
for (int i = 0; i < discoverySites.length; i++)
publishSite(feature, bus, discoverySites[i].getURL(), false);
String updateSite = feature.getUpdateSiteURL();
if (updateSite != null)
publishSite(feature, bus, updateSite, true);
}
/**
* Broadcast a discovery event for the given repository location.
*/
private void publishSite(Feature feature, IProvisioningEventBus bus, String locationString, boolean isEnabled) {
try {
URL siteLocation = new URL(locationString);
bus.publishEvent(new RepositoryEvent(siteLocation, IRepository.TYPE_METADATA, RepositoryEvent.DISCOVERED, isEnabled));
bus.publishEvent(new RepositoryEvent(siteLocation, IRepository.TYPE_ARTIFACT, RepositoryEvent.DISCOVERED, isEnabled));
} catch (MalformedURLException e) {
LogHelper.log(new Status(IStatus.WARNING, Activator.ID, "Feature references invalid site: " + feature.getId(), e)); //$NON-NLS-1$
}
}
}