blob: dc51dabe3d2549564104968ae0571c7d8bd13195 [file] [log] [blame]
/*
* Copyright (c) 2014, 2015 Eike Stepper (Berlin, Germany) 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:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.oomph.targlets.internal.core;
import org.eclipse.oomph.p2.P2Factory;
import org.eclipse.oomph.p2.ProfileDefinition;
import org.eclipse.oomph.p2.Repository;
import org.eclipse.oomph.p2.Requirement;
import org.eclipse.oomph.p2.VersionSegment;
import org.eclipse.oomph.p2.core.BundlePool;
import org.eclipse.oomph.p2.core.P2Util;
import org.eclipse.oomph.p2.core.Profile;
import org.eclipse.oomph.p2.core.ProfileTransaction;
import org.eclipse.oomph.p2.core.ProfileTransaction.CommitContext;
import org.eclipse.oomph.p2.internal.core.CacheUsageConfirmer;
import org.eclipse.oomph.resources.SourceLocator;
import org.eclipse.oomph.targlets.FeatureGenerator;
import org.eclipse.oomph.targlets.IUGenerator;
import org.eclipse.oomph.targlets.Targlet;
import org.eclipse.oomph.targlets.TargletFactory;
import org.eclipse.oomph.targlets.core.ITargletContainer;
import org.eclipse.oomph.targlets.core.ITargletContainerDescriptor.UpdateProblem;
import org.eclipse.oomph.targlets.core.TargletContainerEvent;
import org.eclipse.oomph.targlets.core.WorkspaceIUInfo;
import org.eclipse.oomph.util.HexUtil;
import org.eclipse.oomph.util.IOUtil;
import org.eclipse.oomph.util.ObjectUtil;
import org.eclipse.oomph.util.ReflectUtil;
import org.eclipse.oomph.util.StringUtil;
import org.eclipse.oomph.util.SubMonitor;
import org.eclipse.oomph.util.pde.TargetPlatformRunnable;
import org.eclipse.oomph.util.pde.TargetPlatformUtil;
import org.eclipse.emf.common.CommonPlugin;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.BasicExtendedMetaData;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.util.FeatureMapUtil;
import org.eclipse.emf.ecore.xmi.XMLOptions;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.XMLOptionsImpl;
import org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl;
import org.eclipse.emf.ecore.xml.type.AnyType;
import org.eclipse.emf.ecore.xml.type.XMLTypeFactory;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.preferences.ConfigurationScope;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.equinox.internal.p2.engine.DownloadManager;
import org.eclipse.equinox.internal.p2.engine.InstallableUnitOperand;
import org.eclipse.equinox.internal.p2.engine.InstallableUnitPhase;
import org.eclipse.equinox.internal.p2.engine.Phase;
import org.eclipse.equinox.internal.p2.engine.PhaseSet;
import org.eclipse.equinox.internal.p2.engine.phases.Collect;
import org.eclipse.equinox.internal.p2.engine.phases.Install;
import org.eclipse.equinox.internal.p2.engine.phases.Property;
import org.eclipse.equinox.internal.p2.engine.phases.Uninstall;
import org.eclipse.equinox.internal.p2.metadata.IRequiredCapability;
import org.eclipse.equinox.internal.p2.metadata.InstallableUnit;
import org.eclipse.equinox.internal.p2.metadata.ResolvedInstallableUnit;
import org.eclipse.equinox.internal.p2.metadata.expression.LDAPFilter;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.engine.IPhaseSet;
import org.eclipse.equinox.p2.engine.IProfile;
import org.eclipse.equinox.p2.engine.IProvisioningPlan;
import org.eclipse.equinox.p2.engine.ProvisioningContext;
import org.eclipse.equinox.p2.engine.spi.ProvisioningAction;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IInstallableUnitFragment;
import org.eclipse.equinox.p2.metadata.ILicense;
import org.eclipse.equinox.p2.metadata.IProvidedCapability;
import org.eclipse.equinox.p2.metadata.IRequirement;
import org.eclipse.equinox.p2.metadata.ITouchpointData;
import org.eclipse.equinox.p2.metadata.MetadataFactory;
import org.eclipse.equinox.p2.metadata.MetadataFactory.InstallableUnitDescription;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.metadata.VersionRange;
import org.eclipse.equinox.p2.metadata.expression.ExpressionUtil;
import org.eclipse.equinox.p2.metadata.expression.IExpression;
import org.eclipse.equinox.p2.metadata.expression.IFilterExpression;
import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
import org.eclipse.equinox.p2.planner.IProfileChangeRequest;
import org.eclipse.equinox.p2.publisher.eclipse.BundlesAction;
import org.eclipse.equinox.p2.query.CollectionResult;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.IQueryable;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRequest;
import org.eclipse.equinox.p2.repository.artifact.IFileArtifactRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
import org.eclipse.equinox.spi.p2.publisher.PublisherHelper;
import org.eclipse.pde.core.target.ITargetDefinition;
import org.eclipse.pde.core.target.ITargetLocation;
import org.eclipse.pde.core.target.ITargetLocationFactory;
import org.eclipse.pde.core.target.ITargetPlatformService;
import org.eclipse.pde.core.target.TargetBundle;
import org.eclipse.pde.core.target.TargetFeature;
import org.eclipse.pde.internal.core.target.AbstractBundleContainer;
import org.xml.sax.InputSource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Method;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Eike Stepper
*/
@SuppressWarnings("restriction")
public class TargletContainer extends AbstractBundleContainer implements ITargletContainer
{
public static final String TYPE = "Targlet";
public static final String IU_PROPERTY_SOURCE = "org.eclipse.oomph.targlet.source";
private static final ThreadLocal<Boolean> FORCE_UPDATE = new ThreadLocal<Boolean>();
private static final ThreadLocal<Boolean> MIRRORS = new ThreadLocal<Boolean>();
private static final String A_PDE_TARGET_PLATFORM = "A.PDE.Target.Platform";
private static final String A_PDE_TARGET_PLATFORM_LOWER_CASE = A_PDE_TARGET_PLATFORM.toLowerCase();
private static final String FOLLOW_ARTIFACT_REPOSITORY_REFERENCES = "org.eclipse.equinox.p2.director.followArtifactRepositoryReferences";
private static final byte[] BUFFER = new byte[8192];
private static final String PROP_ARCH = "osgi.arch"; //$NON-NLS-1$
private static final String PROP_OS = "osgi.os"; //$NON-NLS-1$
private static final String PROP_WS = "osgi.ws"; //$NON-NLS-1$
private String id;
private ITargetDefinition targetDefinition;
private final EList<Targlet> targlets = new BasicEList<Targlet>();
public TargletContainer(String id)
{
this.id = id;
// Make the Targlets UI active so that PDE can use Platform.getAdapterManager() to load our registered adapters.
try
{
CommonPlugin.loadClass("org.eclipse.oomph.targlets.ui", "org.eclipse.oomph.targlets.internal.ui.TargletsUIPlugin");
}
catch (Throwable ex)
{
// Ignore.
}
}
/**
* Copies the passed targlets into this targlet container. Modifications of the passed targlets after the call
* to this constructor won't have an impact on this targlet container.
*/
private TargletContainer(String id, Collection<? extends Targlet> targlets)
{
this(id);
basicSetTarglets(targlets);
}
@Override
protected int getResolveBundlesWork()
{
return 999;
}
@Override
protected int getResolveFeaturesWork()
{
return 1;
}
public boolean isContentEqual(AbstractBundleContainer container)
{
if (container instanceof TargletContainer)
{
TargletContainer targletContainer = (TargletContainer)container;
if (targlets.size() != targletContainer.targlets.size())
{
return false;
}
for (Targlet targlet : targletContainer.targlets)
{
Targlet existingTarglet = getTarglet(targlet.getName());
if (existingTarglet == null || !EcoreUtil.equals(existingTarglet, targlet))
{
return false;
}
}
return true;
}
return false;
}
public String getID()
{
return id;
}
public void setID(String newID) throws CoreException
{
if (!ObjectUtil.equals(newID, id))
{
String oldID = id;
id = newID;
TargletContainerDescriptor descriptor = updateTargetDefinition();
TargletContainerEvent event = new TargletContainerEvent.IDChangedEvent(this, descriptor, oldID);
TargletContainerListenerRegistry.INSTANCE.notifyListeners(event, new NullProgressMonitor());
}
}
private TargletContainerDescriptor updateTargetDefinition() throws CoreException
{
clearResolutionStatus();
TargletContainerDescriptor descriptor = getDescriptor();
if (descriptor != null)
{
descriptor.resetUpdateProblem();
}
if (targetDefinition != null)
{
TargetPlatformUtil.runWithTargetPlatformService(new TargetPlatformRunnable<Object>()
{
public Object run(ITargetPlatformService service) throws CoreException
{
service.saveTargetDefinition(targetDefinition);
return null;
}
});
}
return descriptor;
}
@Override
public String getType()
{
return TYPE;
}
public TargletContainerDescriptor getDescriptor()
{
try
{
TargletContainerDescriptorManager manager = TargletContainerDescriptorManager.getInstance();
return manager.getDescriptor(id, new NullProgressMonitor());
}
catch (Exception ex)
{
TargletsCorePlugin.INSTANCE.log(ex);
return null;
}
}
public ITargetDefinition getTargetDefinition()
{
return targetDefinition;
}
/**
* Returns a copy of the targlet with the given name in this targlet container. This copy can be freely modified but the modifications won't have an impact
* on a targlet container unless the copy is set back into a container via {@link #setTarglets(Collection)}.
*/
public Targlet getTarglet(String name)
{
int index = getTargletIndex(name);
if (index != -1)
{
return TargletFactory.eINSTANCE.copyTarglet(targlets.get(index));
}
return null;
}
public int getTargletIndex(String name)
{
for (int i = 0; i < targlets.size(); i++)
{
Targlet targlet = targlets.get(i);
if (ObjectUtil.equals(targlet.getName(), name))
{
return i;
}
}
return -1;
}
public boolean hasTarglet(String name)
{
return getTargletIndex(name) != -1;
}
/**
* Returns a copy of the targlets in this targlet container. This copy can be freely modified but the modifications won't have an impact
* on a targlet container unless the copy is set back into a container via {@link #setTarglets(Collection)}.
*/
public EList<Targlet> getTarglets()
{
return TargletFactory.eINSTANCE.copyTarglets(targlets);
}
/**
* Copies the passed targlets into this targlet container. Modifications of the passed targlets after the call
* to this method won't have an impact on this targlet container.
*/
public void setTarglets(Collection<? extends Targlet> targlets) throws CoreException
{
basicSetTarglets(targlets);
TargletContainerDescriptor descriptor = updateTargetDefinition();
TargletContainerEvent event = new TargletContainerEvent.TargletsChangedEvent(this, descriptor);
TargletContainerListenerRegistry.INSTANCE.notifyListeners(event, new NullProgressMonitor());
}
private void basicSetTarglets(Collection<? extends Targlet> targlets)
{
Set<String> names = new HashSet<String>();
for (Targlet targlet : targlets)
{
String name = targlet.getName();
if (!names.add(name))
{
throw new IllegalArgumentException("Duplicate targlet name: " + name);
}
}
this.targlets.clear();
this.targlets.addAll(TargletFactory.eINSTANCE.copyTarglets(targlets));
}
@Override
public String serialize()
{
try
{
return Persistence.toXML(id, targlets).toString();
}
catch (Exception ex)
{
TargletsCorePlugin.INSTANCE.log(ex);
return null;
}
}
public boolean isIncludeSources()
{
for (Targlet targlet : targlets)
{
if (targlet.isIncludeSources())
{
return true;
}
}
return false;
}
public boolean isIncludeAllPlatforms()
{
for (Targlet targlet : targlets)
{
if (targlet.isIncludeAllPlatforms())
{
return true;
}
}
return false;
}
public boolean isIncludeAllRequirements()
{
for (Targlet targlet : targlets)
{
if (!targlet.isIncludeAllRequirements())
{
return false;
}
}
return true;
}
public String getEnvironmentProperties()
{
StringBuilder builder = new StringBuilder();
String ws = targetDefinition.getWS();
if (ws == null)
{
ws = Platform.getWS();
}
builder.append(PROP_WS);
builder.append("="); //$NON-NLS-1$
builder.append(ws);
builder.append(","); //$NON-NLS-1$
String os = targetDefinition.getOS();
if (os == null)
{
os = Platform.getOS();
}
builder.append(PROP_OS);
builder.append("="); //$NON-NLS-1$
builder.append(os);
builder.append(","); //$NON-NLS-1$
String arch = targetDefinition.getArch();
if (arch == null)
{
arch = Platform.getOSArch();
}
builder.append(PROP_ARCH);
builder.append("="); //$NON-NLS-1$
builder.append(arch);
builder.append(",org.eclipse.swt.buildtime=true");
return builder.toString();
}
public String getNLProperty()
{
String nl = targetDefinition.getNL();
if (nl == null)
{
nl = Platform.getNL();
}
return nl;
}
@Override
public String toString()
{
return "Targlet Container " + id;
}
@Override
public String getLocation(boolean resolve) throws CoreException
{
TargletContainerDescriptorManager manager = TargletContainerDescriptorManager.getInstance();
TargletContainerDescriptor descriptor = manager.getDescriptor(id, new NullProgressMonitor());
return descriptor.getInstallLocation().getAbsolutePath();
}
public String getDigest()
{
String environmentProperties = getEnvironmentProperties();
String nlProperty = getNLProperty();
return createDigest(id, environmentProperties, nlProperty, targlets);
}
@Override
protected void associateWithTarget(ITargetDefinition target)
{
super.associateWithTarget(target);
targetDefinition = target;
}
@Override
protected TargetBundle[] resolveBundles(ITargetDefinition target, IProgressMonitor monitor) throws CoreException
{
resolveUnits(monitor);
return fBundles;
}
@Override
protected TargetFeature[] resolveFeatures(ITargetDefinition target, IProgressMonitor monitor) throws CoreException
{
// All work has been done in resolveBundles() already.
return fFeatures;
}
private void resolveUnits(IProgressMonitor monitor) throws CoreException
{
try
{
SubMonitor progress = SubMonitor.convert(monitor, 100).detectCancelation();
TargletContainerDescriptorManager manager = TargletContainerDescriptorManager.getInstance();
String environmentProperties = getEnvironmentProperties();
String nlProperty = getNLProperty();
String digest = createDigest(id, environmentProperties, nlProperty, targlets);
TargletContainerDescriptor descriptor = manager.getDescriptor(id, progress.newChild(4));
progress.childDone();
boolean isDisplayThread = isDisplayThread();
Profile profile = descriptor.getWorkingProfile();
if (profile == null || //
!descriptor.getWorkingDigest().equals(digest) && !isDisplayThread && descriptor.getUpdateProblem() == null || //
FORCE_UPDATE.get() == Boolean.TRUE)
{
try
{
if (isDisplayThread)
{
throw new CoreException(Status.CANCEL_STATUS);
}
Profile newProfile = updateProfile(environmentProperties, nlProperty, digest, progress.newChild(86));
if (newProfile != null)
{
if (profile != null && !profile.getProfileId().equals(newProfile.getProfileId()))
{
profile.delete();
}
profile = newProfile;
}
}
catch (CoreException ex)
{
if (profile == null)
{
// This just leads to logging further down.
throw ex;
}
}
}
else
{
progress.skipped(86);
}
generateUnits(descriptor, profile, progress.newChild(10));
progress.done();
}
catch (Throwable t)
{
TargletsCorePlugin.INSTANCE.coreException(t);
}
}
private void generateUnits(TargletContainerDescriptor descriptor, IProfile profile, IProgressMonitor monitor) throws CoreException
{
SubMonitor progress = SubMonitor.convert(monitor, 100).detectCancelation();
List<TargetBundle> bundles = new ArrayList<TargetBundle>();
List<TargetFeature> features = new ArrayList<TargetFeature>();
if (profile != null)
{
IQueryResult<IInstallableUnit> result = profile.query(QueryUtil.createIUAnyQuery(), progress.newChild(2));
generateUnits(descriptor, result.toUnmodifiableSet(), bundles, features, progress.newChild(98));
}
fBundles = bundles.toArray(new TargetBundle[bundles.size()]);
fFeatures = features.toArray(new TargetFeature[features.size()]);
progress.done();
}
private void generateUnits(TargletContainerDescriptor descriptor, Set<IInstallableUnit> units, List<TargetBundle> bundles, List<TargetFeature> features,
IProgressMonitor monitor) throws CoreException
{
SubMonitor progress = SubMonitor.convert(monitor, units.size()).detectCancelation();
IFileArtifactRepository cache = descriptor.getBundlePool().getFileArtifactRepository();
for (IInstallableUnit unit : units)
{
if (isOSGiBundle(unit))
{
generateBundle(unit, cache, bundles);
}
else if (isFeatureJar(unit))
{
generateFeature(unit, cache, features);
}
progress.worked();
}
progress.done();
}
private void generateBundle(IInstallableUnit unit, IFileArtifactRepository repo, List<TargetBundle> bundles) throws CoreException
{
Collection<IArtifactKey> artifacts = unit.getArtifacts();
for (Iterator<IArtifactKey> it = artifacts.iterator(); it.hasNext();)
{
File file = repo.getArtifactFile(it.next());
if (file != null)
{
TargetBundle bundle = new TargetBundle(file);
bundles.add(bundle);
}
}
}
private void generateFeature(IInstallableUnit unit, IFileArtifactRepository repo, List<TargetFeature> features) throws CoreException
{
Collection<IArtifactKey> artifacts = unit.getArtifacts();
for (Iterator<IArtifactKey> it = artifacts.iterator(); it.hasNext();)
{
File file = repo.getArtifactFile(it.next());
if (file != null)
{
TargetFeature feature = new TargetFeature(file);
features.add(feature);
}
}
}
public void forceUpdate(boolean activateTargetDefinition, boolean mirrors, IProgressMonitor monitor) throws CoreException
{
try
{
FORCE_UPDATE.set(Boolean.TRUE);
MIRRORS.set(mirrors ? Boolean.TRUE : false);
// Clear the resolution statuses of the involved targlet containers.
for (ITargetLocation targetLocation : targetDefinition.getTargetLocations())
{
if (targetLocation instanceof ITargletContainer)
{
TargletContainer targletContainer = (TargletContainer)targetLocation;
targletContainer.clearResolutionStatus();
}
}
if (activateTargetDefinition || TargetPlatformUtil.isActiveTargetDefinition(targetDefinition))
{
// If the target definition is currently active then use PDE's LoadTargetDefinitionJob so that the WorkspaceIUImporter gets triggered.
TargetPlatformUtil.activateTargetDefinition(targetDefinition, monitor);
}
else
{
// Otherwise just update the profile and resolve.
targetDefinition.resolve(monitor);
}
TargletContainerDescriptorManager manager = TargletContainerDescriptorManager.getInstance();
TargletContainerDescriptor descriptor = manager.getDescriptor(id, monitor);
UpdateProblem updateProblem = descriptor.getUpdateProblem();
if (updateProblem != null)
{
TargletsCorePlugin.INSTANCE.coreException(new CoreException(updateProblem));
}
}
finally
{
MIRRORS.remove();
FORCE_UPDATE.remove();
}
}
public IStatus updateProfile(IProgressMonitor monitor)
{
try
{
String environmentProperties = getEnvironmentProperties();
String nlProperty = getNLProperty();
String digest = createDigest(id, environmentProperties, nlProperty, targlets);
updateProfile(environmentProperties, nlProperty, digest, monitor);
return Status.OK_STATUS;
}
catch (CoreException ex)
{
return ex.getStatus();
}
}
private Profile updateProfile(String environmentProperties, String nlProperty, String digest, IProgressMonitor monitor) throws CoreException
{
SubMonitor progress = SubMonitor.convert(monitor, 100).detectCancelation();
TargletContainerDescriptorManager manager = TargletContainerDescriptorManager.getInstance();
TargletContainerDescriptor descriptor = manager.getDescriptor(id, progress.newChild());
final Profile profile = descriptor.startUpdateTransaction(environmentProperties, nlProperty, digest, progress.newChild());
ProfileTransaction transaction = profile.change().setRemoveExistingInstallableUnits(true);
transaction.setMirrors(MIRRORS.get() == Boolean.TRUE);
IProvisioningAgent provisioningAgent = profile.getAgent().getProvisioningAgent();
CacheUsageConfirmer cacheUsageConfirmer = TargletsCorePlugin.INSTANCE.getCacheUsageConfirmer();
CacheUsageConfirmer oldCacheUsageConfirmer = (CacheUsageConfirmer)provisioningAgent.getService(CacheUsageConfirmer.SERVICE_NAME);
IEclipsePreferences garbageCollectorPreferences = ConfigurationScope.INSTANCE.getNode("org.eclipse.equinox.p2.garbagecollector");
String oldGCEnabled = garbageCollectorPreferences.get("gc_enabled", null);
garbageCollectorPreferences.putBoolean("gc_enabled", false);
try
{
if (cacheUsageConfirmer != null)
{
provisioningAgent.registerService(CacheUsageConfirmer.SERVICE_NAME, cacheUsageConfirmer);
}
ProfileDefinition profileDefinition = transaction.getProfileDefinition();
profileDefinition.setIncludeSourceBundles(isIncludeSources());
final EList<Requirement> rootRequirements = profileDefinition.getRequirements();
rootRequirements.clear();
EList<Repository> repositories = profileDefinition.getRepositories();
repositories.clear();
WorkspaceIUAnalyzer workspaceIUAnalyzer = analyzeWorkspaceIUs(rootRequirements, repositories, progress);
if (rootRequirements.isEmpty())
{
descriptor.rollbackUpdateTransaction(null, new NullProgressMonitor());
return null;
}
TargletCommitContext commitContext = new TargletCommitContext(profile, workspaceIUAnalyzer, isIncludeAllPlatforms(), isIncludeAllRequirements());
transaction.commit(commitContext, progress.newChild());
Map<IInstallableUnit, WorkspaceIUInfo> requiredProjects = getRequiredProjects(profile, workspaceIUAnalyzer.getWorkspaceIUInfos(), progress.newChild());
descriptor.commitUpdateTransaction(digest, requiredProjects.values(), progress.newChild());
TargletContainerEvent event = new TargletContainerEvent.ProfileUpdateSucceededEvent(this, descriptor, profile, commitContext.getArtificialRoot(),
commitContext.getMetadataRepositories(), commitContext.getProvisioningPlan(), requiredProjects);
TargletContainerListenerRegistry.INSTANCE.notifyListeners(event, progress.newChild());
monitor.subTask("Targlet container profile update completed");
}
catch (Throwable t)
{
descriptor.rollbackUpdateTransaction(t, new NullProgressMonitor());
UpdateProblem updateProblem = descriptor.getUpdateProblem();
if (updateProblem != null)
{
TargletContainerEvent event = new TargletContainerEvent.ProfileUpdateFailedEvent(this, descriptor, updateProblem);
TargletContainerListenerRegistry.INSTANCE.notifyListeners(event, new NullProgressMonitor());
}
TargletsCorePlugin.INSTANCE.coreException(t);
}
finally
{
if (oldGCEnabled == null)
{
garbageCollectorPreferences.remove("gc_enabled");
}
else
{
garbageCollectorPreferences.put("gc_enabled", oldGCEnabled);
}
if (cacheUsageConfirmer != null && oldCacheUsageConfirmer != null)
{
provisioningAgent.registerService(CacheUsageConfirmer.SERVICE_NAME, oldCacheUsageConfirmer);
}
}
progress.done();
return profile;
}
private WorkspaceIUAnalyzer analyzeWorkspaceIUs(final EList<Requirement> rootRequirements, EList<Repository> repositories, SubMonitor progress)
throws CoreException
{
WorkspaceIUAnalyzer workspaceIUAnalyzer = new WorkspaceIUAnalyzer();
for (Targlet targlet : targlets)
{
EList<IUGenerator> effectiveIUGenerators = effectiveIUGenerators(targlet);
EList<IInstallableUnit> ius = new BasicEList<IInstallableUnit>();
for (SourceLocator sourceLocator : targlet.getSourceLocators())
{
ius.addAll(workspaceIUAnalyzer.analyze(sourceLocator, effectiveIUGenerators, progress.newChild()));
}
for (Requirement requirement : EcoreUtil.copyAll(targlet.getRequirements()))
{
String namespace = requirement.getNamespace();
String name = requirement.getName();
if (StringUtil.isEmpty(namespace) || StringUtil.isEmpty(name) || requirement.getVersionRange() == null)
{
continue;
}
if ("*".equals(name) && IInstallableUnit.NAMESPACE_IU_ID.equals(namespace))
{
for (IInstallableUnit iu : ius)
{
if ("true".equalsIgnoreCase(iu.getProperty("org.eclipse.equinox.p2.type.category")))
{
continue;
}
rootRequirements
.add(P2Factory.eINSTANCE.createRequirement(iu.getId(), requirement.getVersionRange(), requirement.isOptional(), requirement.isGreedy()));
}
continue;
}
rootRequirements.add(requirement);
}
for (Repository repository : EcoreUtil.copyAll(targlet.getActiveRepositories()))
{
if (!StringUtil.isEmpty(repository.getURL()))
{
repositories.add(repository);
}
}
}
workspaceIUAnalyzer.adjustOmniRootRequirements(rootRequirements);
IStatus status = workspaceIUAnalyzer.getStatus();
TargletsCorePlugin.INSTANCE.coreException(status);
return workspaceIUAnalyzer;
}
private static EList<IUGenerator> effectiveIUGenerators(Targlet targlet)
{
EList<IUGenerator> effectiveInstallableUnitGenerators = targlet.getInstallableUnitGenerators();
if (effectiveInstallableUnitGenerators.isEmpty())
{
effectiveInstallableUnitGenerators = IUGenerator.DEFAULTS;
}
return effectiveInstallableUnitGenerators;
}
private static String createDigest(String id, String environmentProperties, String nlProperty, EList<Targlet> targlets)
{
InputStream stream = null;
try
{
Writer writer = Persistence.toXML(id, targlets);
writer.write("\n<!-- Environment Properties: ");
writer.write(environmentProperties);
writer.write(" -->");
writer.write("\n<!-- NL Property: ");
writer.write(nlProperty);
writer.write(" -->\n");
final MessageDigest digest = MessageDigest.getInstance("SHA-1");
stream = new FilterInputStream(new ByteArrayInputStream(writer.toString().getBytes("UTF-8")))
{
@Override
public int read() throws IOException
{
for (;;)
{
int ch = super.read();
switch (ch)
{
case -1:
return -1;
case 10:
case 13:
continue;
}
digest.update((byte)ch);
return ch;
}
}
@Override
public int read(byte[] b, int off, int len) throws IOException
{
int read = super.read(b, off, len);
if (read == -1)
{
return -1;
}
for (int i = off; i < off + read; i++)
{
byte c = b[i];
if (c == 10 || c == 13)
{
if (i + 1 < off + read)
{
System.arraycopy(b, i + 1, b, i, read - i - 1);
--i;
}
--read;
}
}
digest.update(b, off, read);
return read;
}
};
synchronized (BUFFER)
{
while (stream.read(BUFFER) != -1)
{
// Do nothing
}
}
return HexUtil.bytesToHex(digest.digest());
}
catch (RuntimeException ex)
{
throw ex;
}
catch (Exception ex)
{
throw new RuntimeException(ex);
}
finally
{
IOUtil.close(stream);
}
}
private static boolean isOSGiBundle(IInstallableUnit unit)
{
return providesNamespace(unit, "osgi.bundle");
}
private static boolean isFeatureJar(IInstallableUnit unit)
{
return providesNamespace(unit, "org.eclipse.update.feature");
}
private static boolean isDisplayThread()
{
try
{
Class<?> displayClass = CommonPlugin.loadClass("org.eclipse.swt", "org.eclipse.swt.widgets.Display");
Method getCurrentMethod = ReflectUtil.getMethod(displayClass, "getCurrent");
return ReflectUtil.invokeMethod(getCurrentMethod, null) != null;
}
catch (Throwable ex)
{
//$FALL-THROUGH$
}
return false;
}
private static boolean providesNamespace(IInstallableUnit unit, String namespace)
{
for (IProvidedCapability providedCapability : unit.getProvidedCapabilities())
{
if (namespace.equals(providedCapability.getNamespace()))
{
return true;
}
}
return false;
}
private static Map<IInstallableUnit, WorkspaceIUInfo> getRequiredProjects(IProfile profile, Map<IInstallableUnit, WorkspaceIUInfo> allProjects,
IProgressMonitor monitor)
{
Map<WorkspaceIUInfo, IInstallableUnit> mainIUs = new HashMap<WorkspaceIUInfo, IInstallableUnit>();
for (Map.Entry<IInstallableUnit, WorkspaceIUInfo> entry : allProjects.entrySet())
{
IInstallableUnit iu = entry.getKey();
if ("true".equals(iu.getProperty(WorkspaceIUAnalyzer.IU_PROPERTY_WORKSPACE_MAIN)))
{
mainIUs.put(entry.getValue(), iu);
}
}
Map<IInstallableUnit, WorkspaceIUInfo> result = new HashMap<IInstallableUnit, WorkspaceIUInfo>();
for (IInstallableUnit iu : P2Util.asIterable(profile.query(QueryUtil.createIUAnyQuery(), monitor)))
{
if ("true".equals(iu.getProperty(TargletContainer.IU_PROPERTY_SOURCE)))
{
continue;
}
WorkspaceIUInfo info = allProjects.get(iu);
if (info != null)
{
IInstallableUnit mainIU = mainIUs.get(info);
if (mainIU != null)
{
result.put(mainIU, info);
}
}
}
return result;
}
/**
* @author Eike Stepper
*/
private static final class TargletCommitContext extends CommitContext
{
private static final Pattern OSGI_PROPERTY_FILTER = Pattern.compile("(!?)\\((osgi.arch|osgi.os|osgi.ws)=([^)]+)\\)");
private static final String NATIVE_ARTIFACTS = "nativeArtifacts"; //$NON-NLS-1$
private final Profile profile;
private final WorkspaceIUAnalyzer workspaceIUAnalyzer;
private IProvisioningPlan provisioningPlan;
private IInstallableUnit artificialRoot;
private List<IMetadataRepository> metadataRepositories;
private boolean isIncludeAllPlatforms;
private boolean isIncludeAllRequirements;
public TargletCommitContext(Profile profile, WorkspaceIUAnalyzer workspaceIUAnalyzer, boolean isIncludeAllPlatforms, boolean isIncludeAllRequirements)
{
this.profile = profile;
this.workspaceIUAnalyzer = workspaceIUAnalyzer;
this.isIncludeAllPlatforms = isIncludeAllPlatforms;
this.isIncludeAllRequirements = isIncludeAllRequirements;
}
public IProvisioningPlan getProvisioningPlan()
{
return provisioningPlan;
}
public final IInstallableUnit getArtificialRoot()
{
return artificialRoot;
}
public List<IMetadataRepository> getMetadataRepositories()
{
return metadataRepositories;
}
@Override
public ProvisioningContext createProvisioningContext(ProfileTransaction transaction, final IProfileChangeRequest profileChangeRequest) throws CoreException
{
IProvisioningAgent provisioningAgent = transaction.getProfile().getAgent().getProvisioningAgent();
ProvisioningContext provisioningContext = new ProvisioningContext(provisioningAgent)
{
private CollectionResult<IInstallableUnit> metadata;
@Override
public IQueryable<IInstallableUnit> getMetadata(IProgressMonitor monitor)
{
if (metadata == null)
{
Map<IInstallableUnit, WorkspaceIUInfo> workspaceIUInfos = workspaceIUAnalyzer.getWorkspaceIUInfos();
Map<String, Version> workspaceIUVersions = workspaceIUAnalyzer.getIUVersions();
Set<IInstallableUnit> originalWorkspaceIUs = new HashSet<IInstallableUnit>(workspaceIUInfos.keySet());
Set<IInstallableUnit> ius = new LinkedHashSet<IInstallableUnit>();
Map<IU, IInstallableUnit> idToIUMap = new HashMap<IU, IInstallableUnit>();
generateWorkspaceSourceIUs(ius, workspaceIUVersions, idToIUMap, monitor);
ius.add(createPDETargetPlatformIU());
IQueryResult<IInstallableUnit> metadataResult = super.getMetadata(monitor).query(QueryUtil.createIUAnyQuery(), monitor);
Set<IRequirement> licenseRequirements = new HashSet<IRequirement>();
Set<IRequirement> workspaceRequirements = new HashSet<IRequirement>();
Set<IRequirement> binaryRequirements = new HashSet<IRequirement>();
for (IInstallableUnit iu : P2Util.asIterable(metadataResult))
{
TargletsCorePlugin.checkCancelation(monitor);
binaryRequirements.addAll(iu.getRequirements());
ius.add(createGeneralizedIU(iu));
// If the binary IU corresponds to a synthetic source IU...
IInstallableUnit workspaceIU = idToIUMap.get(new IU(iu));
if (workspaceIU == null)
{
workspaceIU = idToIUMap.get(new IU(iu.getId(), Version.emptyVersion));
}
if (workspaceIU != null)
{
// Ensure that if this binary IU is resolved that the corresponding source file is imported in the workspace.
WorkspaceIUInfo info = workspaceIUInfos.get(workspaceIU);
workspaceIUInfos.put(iu, info);
// We can remove our synthetic IU to ensure that, whenever possible, a binary resolution for it is included in the TP.
// That's only necessary if the IU is a singleton.
if (workspaceIU.isSingleton() || "true".equals(workspaceIU.getProperty(InstallableUnitDescription.PROP_TYPE_GROUP)))
{
ius.remove(workspaceIU);
}
// If the workspaceIU has any requirements not in the binary IU, then include those.
LOOP: for (IRequirement workspaceRequirement : workspaceIU.getRequirements())
{
if (workspaceRequirement instanceof IRequiredCapability)
{
IRequiredCapability workspaceRequiredCapability = (IRequiredCapability)workspaceRequirement;
String namespace = workspaceRequiredCapability.getNamespace();
String name = workspaceRequiredCapability.getName();
for (IRequirement requirement : iu.getRequirements())
{
if (requirement instanceof IRequiredCapability)
{
IRequiredCapability requiredCapability = (IRequiredCapability)requirement;
if (namespace.equals(requiredCapability.getNamespace()) && name.equals(requiredCapability.getName()))
{
// It's already included, perhaps with a different version range, but we'll ignore it.
continue LOOP;
}
}
}
// If it's an IU or bundle requirement...
if (IInstallableUnit.NAMESPACE_IU_ID.equals(namespace) || BundlesAction.CAPABILITY_NS_OSGI_BUNDLE.equals(namespace))
{
// If it resolves to a workspace IU that's a singleton, generalize the requirement to include any version of that IU, because resolving to
// any version will result in the import of the project.
IInstallableUnit requiredWorkspaceIU = idToIUMap.get(new IU(name, Version.emptyVersion));
if (requiredWorkspaceIU != null
&& (requiredWorkspaceIU.isSingleton() || "true".equals(requiredWorkspaceIU.getProperty(InstallableUnitDescription.PROP_TYPE_GROUP))))
{
workspaceRequirements
.add(MetadataFactory.createRequirement(namespace, name, VersionRange.emptyRange, workspaceRequiredCapability.getFilter(),
workspaceRequiredCapability.getMin(), workspaceRequiredCapability.getMax(), workspaceRequiredCapability.isGreedy()));
continue LOOP;
}
}
}
// Otherwise add the requirement as is.
workspaceRequirements.add(workspaceRequirement);
}
// If there this workspace IU has a license...
String licenseFeatureID = workspaceIU.getProperty(FeatureGenerator.PROP_REQUIRED_LICENCSE_FEATURE_ID);
if (licenseFeatureID != null)
{
// Keep a requirement for this IU because binary IUs are generally not installed for license feature dependencies.
VersionRange versionRange = new VersionRange(workspaceIU.getProperty(FeatureGenerator.PROP_REQUIRED_LICENCSE_FEATURE_VERSION_RANGE));
IRequirement requirement = MetadataFactory.createRequirement(IInstallableUnit.NAMESPACE_IU_ID, licenseFeatureID, versionRange, null, false,
false);
licenseRequirements.add(requirement);
}
}
}
// If we need license requirements.
if (!licenseRequirements.isEmpty())
{
// Build an artificial unit that requires all the license features.
InstallableUnitDescription requiredLicensesDescription = new InstallableUnitDescription();
requiredLicensesDescription.setId("required_licenses");
requiredLicensesDescription.setVersion(Version.createOSGi(1, 0, 0));
requiredLicensesDescription.setArtifacts(new IArtifactKey[0]);
requiredLicensesDescription.setProperty(InstallableUnitDescription.PROP_TYPE_GROUP, Boolean.TRUE.toString());
requiredLicensesDescription.setCapabilities(new IProvidedCapability[] { MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID,
requiredLicensesDescription.getId(), requiredLicensesDescription.getVersion()) });
requiredLicensesDescription.addRequirements(licenseRequirements);
IInstallableUnit requiredLicensesIU = MetadataFactory.createInstallableUnit(requiredLicensesDescription);
ius.add(requiredLicensesIU);
profileChangeRequest.add(requiredLicensesIU);
}
// If we need source requirements.
workspaceRequirements.removeAll(binaryRequirements);
if (!workspaceRequirements.isEmpty())
{
// Build an artificial unit that requires all the license features.
InstallableUnitDescription workspaceRequirementsDescription = new InstallableUnitDescription();
workspaceRequirementsDescription.setId("workspace_requirements");
workspaceRequirementsDescription.setVersion(Version.createOSGi(1, 0, 0));
workspaceRequirementsDescription.setArtifacts(new IArtifactKey[0]);
workspaceRequirementsDescription.setProperty(InstallableUnitDescription.PROP_TYPE_GROUP, Boolean.TRUE.toString());
workspaceRequirementsDescription
.setCapabilities(new IProvidedCapability[] { MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID,
workspaceRequirementsDescription.getId(), workspaceRequirementsDescription.getVersion()) });
workspaceRequirementsDescription.addRequirements(workspaceRequirements);
IInstallableUnit workspaceRequirementsIU = MetadataFactory.createInstallableUnit(workspaceRequirementsDescription);
ius.add(workspaceRequirementsIU);
profileChangeRequest.add(workspaceRequirementsIU);
}
Set<IInstallableUnit> remainingWorkspaceIUs = new HashSet<IInstallableUnit>(ius);
remainingWorkspaceIUs.retainAll(originalWorkspaceIUs);
for (IInstallableUnit iu : remainingWorkspaceIUs)
{
Collection<IRequirement> requirements = iu.getRequirements();
int size = requirements.size();
IRequirement[] generalizedRequirements = requirements.toArray(new IRequirement[size]);
boolean needsGeneralization = false;
for (int i = 0; i < size; ++i)
{
IRequirement workspaceRequirement = generalizedRequirements[i];
if (workspaceRequirement instanceof IRequiredCapability)
{
IRequiredCapability workspaceRequiredCapability = (IRequiredCapability)workspaceRequirement;
VersionRange versionRange = workspaceRequiredCapability.getRange();
if (!VersionRange.emptyRange.equals(versionRange))
{
String namespace = workspaceRequiredCapability.getNamespace();
String name = workspaceRequiredCapability.getName();
if (IInstallableUnit.NAMESPACE_IU_ID.equals(namespace) || BundlesAction.CAPABILITY_NS_OSGI_BUNDLE.equals(namespace))
{
IInstallableUnit requiredWorkspaceIU = idToIUMap.get(new IU(name, Version.emptyVersion));
if (requiredWorkspaceIU != null && !ius.contains(requiredWorkspaceIU)
&& (requiredWorkspaceIU.isSingleton() || "true".equals(requiredWorkspaceIU.getProperty(InstallableUnitDescription.PROP_TYPE_GROUP))))
{
needsGeneralization = true;
generalizedRequirements[i] = MetadataFactory.createRequirement(namespace, name, VersionRange.emptyRange,
workspaceRequiredCapability.getFilter(), workspaceRequiredCapability.getMin(), workspaceRequiredCapability.getMax(),
workspaceRequiredCapability.isGreedy());
}
}
}
}
}
if (needsGeneralization)
{
((InstallableUnit)iu).setRequiredCapabilities(generalizedRequirements);
}
}
metadata = new CollectionResult<IInstallableUnit>(ius);
}
return metadata;
}
private IInstallableUnit createGeneralizedIU(IInstallableUnit iu)
{
// If we're not including all platform, no generalization is needed.
if (!isIncludeAllPlatforms && isIncludeAllRequirements)
{
return iu;
}
// Determine the generalized IU filter.
IMatchExpression<IInstallableUnit> filter = iu.getFilter();
IMatchExpression<IInstallableUnit> generalizedFilter = isIncludeAllPlatforms ? generalize(filter) : filter;
boolean needsGeneralization = filter != generalizedFilter;
// Determine the generalized requirement filters.
Collection<IRequirement> requirements = iu.getRequirements();
IRequirement[] generalizedRequirements = requirements.toArray(new IRequirement[requirements.size()]);
for (int i = 0; i < generalizedRequirements.length; ++i)
{
IRequirement requirement = generalizedRequirements[i];
IMatchExpression<IInstallableUnit> requirementFilter = requirement.getFilter();
IMatchExpression<IInstallableUnit> generalizedRequirementFilter = isIncludeAllPlatforms ? generalize(requirementFilter) : filter;
// If the filter needs generalization, create a clone of the requirement, with the generalized filter replacement.
if (requirementFilter != filter || !isIncludeAllRequirements && requirement.getMin() != 0)
{
needsGeneralization = true;
// IRequirement generalizedRequirement = MetadataFactory.createRequirement(requirement.getMatches(), generalizedRequirementFilter,
// requirement.getMin(), requirement.getMax(), requirement.isGreedy(), requirement.getDescription());
IRequirement generalizedRequirement = MetadataFactory.createRequirement(requirement.getMatches(), generalizedRequirementFilter, 0,
requirement.getMax(), true, requirement.getDescription());
generalizedRequirements[i] = generalizedRequirement;
}
}
// If none of the filters or slicer-mode lower bounds need generalization, the original IU can be used.
if (!needsGeneralization)
{
return iu;
}
// Create a description that clones the IU with the generalized filter and slicer-mode lower bound replacements.
InstallableUnitDescription description;
if (iu instanceof IInstallableUnitFragment)
{
IInstallableUnitFragment installableUnitFragment = (IInstallableUnitFragment)iu;
MetadataFactory.InstallableUnitFragmentDescription fragmentDescription = new MetadataFactory.InstallableUnitFragmentDescription();
Collection<IRequirement> host = installableUnitFragment.getHost();
fragmentDescription.setHost(host.toArray(new IRequirement[host.size()]));
description = fragmentDescription;
}
else
{
description = new MetadataFactory.InstallableUnitDescription();
}
description.setId(iu.getId());
description.setVersion(iu.getVersion());
Collection<IArtifactKey> artifacts = iu.getArtifacts();
description.setArtifacts(artifacts.toArray(new IArtifactKey[artifacts.size()]));
Collection<IProvidedCapability> providedCapabilities = iu.getProvidedCapabilities();
description.setCapabilities(providedCapabilities.toArray(new IProvidedCapability[providedCapabilities.size()]));
description.setCopyright(iu.getCopyright());
description.setFilter(generalizedFilter);
Collection<ILicense> licenses = iu.getLicenses();
description.setLicenses(licenses.toArray(new ILicense[licenses.size()]));
Collection<IRequirement> metaRequirements = iu.getMetaRequirements();
description.setMetaRequirements(metaRequirements.toArray(new IRequirement[metaRequirements.size()]));
description.setRequirements(generalizedRequirements);
description.setSingleton(iu.isSingleton());
description.setTouchpointType(iu.getTouchpointType());
description.setUpdateDescriptor(iu.getUpdateDescriptor());
for (Iterator<Map.Entry<String, String>> iterator = iu.getProperties().entrySet().iterator(); iterator.hasNext();)
{
Map.Entry<String, String> entry = iterator.next();
description.setProperty(entry.getKey(), entry.getValue());
}
for (ITouchpointData touchpointData : iu.getTouchpointData())
{
description.addTouchpointData(touchpointData);
}
return MetadataFactory.createInstallableUnit(description);
}
private IMatchExpression<IInstallableUnit> generalize(IMatchExpression<IInstallableUnit> filter)
{
if (filter == null)
{
return null;
}
// Lazily determine if any parameter needs generalization.
Object[] generalizedParameters = null;
Object[] parameters = filter.getParameters();
for (int i = 0; i < parameters.length; ++i)
{
Object parameter = parameters[i];
if (parameter instanceof LDAPFilter)
{
String value = parameter.toString();
Matcher matcher = OSGI_PROPERTY_FILTER.matcher(value);
if (matcher.find())
{
// If the pattern matches, we need to generalize the parameters.
if (generalizedParameters == null)
{
// Copy over all the parameters.
// The ones that need generalization will be replaced.
generalizedParameters = new Object[parameters.length];
System.arraycopy(parameters, 0, generalizedParameters, 0, parameters.length);
}
// Build the replacement expression
StringBuffer result = new StringBuffer();
if (matcher.group(1).length() == 0)
{
matcher.appendReplacement(result, "($2=*)");
}
else
{
matcher.appendReplacement(result, "!($2=nothing)");
}
// Handle all the remaining matches the same way.
while (matcher.find())
{
if (matcher.group(1).length() == 0)
{
matcher.appendReplacement(result, "($2=*)");
}
else
{
matcher.appendReplacement(result, "!($2=nothing)");
}
}
// Complete the replacements, parse it back into an LDAP filter, and replace this parameter.
matcher.appendTail(result);
IFilterExpression ldap = ExpressionUtil.parseLDAP(result.toString());
generalizedParameters[i] = ldap;
}
}
}
// If one of the parameters needed to be generalized...
if (generalizedParameters != null)
{
// Parse the filter expression and create a new match expressions with the same filter but the generalized parameters.
IExpression expression = ExpressionUtil.parse(filter.toString());
return ExpressionUtil.getFactory().matchExpression(expression, generalizedParameters);
}
// Otherwise, return the original filter.
return filter;
}
private void generateWorkspaceSourceIUs(Set<IInstallableUnit> ius, Map<String, Version> ids, Map<IU, IInstallableUnit> idToIUMap,
IProgressMonitor monitor)
{
Map<IInstallableUnit, WorkspaceIUInfo> workspaceSourceIUInfos = new HashMap<IInstallableUnit, WorkspaceIUInfo>();
Map<IInstallableUnit, WorkspaceIUInfo> workspaceIUInfos = workspaceIUAnalyzer.getWorkspaceIUInfos();
for (IInstallableUnit iu : workspaceIUInfos.keySet())
{
TargletsCorePlugin.checkCancelation(monitor);
String id = iu.getId();
ius.add(createGeneralizedIU(iu));
idToIUMap.put(new IU(iu), iu);
if (id.endsWith(Requirement.PROJECT_SUFFIX))
{
continue;
}
String suffix = "";
if (id.endsWith(Requirement.FEATURE_SUFFIX))
{
id = id.substring(0, id.length() - Requirement.FEATURE_SUFFIX.length());
suffix = Requirement.FEATURE_SUFFIX;
}
InstallableUnitDescription description = new MetadataFactory.InstallableUnitDescription();
String workspaceSourceID = id + ".source" + suffix;
description.setId(workspaceSourceID);
Version version = iu.getVersion();
description.setVersion(version);
for (Map.Entry<String, String> property : iu.getProperties().entrySet())
{
TargletsCorePlugin.checkCancelation(monitor);
String key = property.getKey();
if (!WorkspaceIUAnalyzer.IU_PROPERTY_WORKSPACE_MAIN.equals(key))
{
String value = property.getValue();
if ("org.eclipse.equinox.p2.name".equals(key))
{
value = "Source for " + value;
}
description.setProperty(key, value);
}
}
description.setTouchpointType(PublisherHelper.TOUCHPOINT_OSGI);
description.setProperty(IU_PROPERTY_SOURCE, Boolean.TRUE.toString());
description.addProvidedCapabilities(Collections
.singleton(MetadataFactory.createProvidedCapability(IInstallableUnit.NAMESPACE_IU_ID, description.getId(), description.getVersion())));
IInstallableUnit workspaceSourceIU = MetadataFactory.createInstallableUnit(description);
ius.add(workspaceSourceIU);
ids.put(workspaceSourceID, version);
idToIUMap.put(new IU(workspaceSourceIU), workspaceSourceIU);
WorkspaceIUInfo info = workspaceIUInfos.get(iu);
workspaceSourceIUInfos.put(workspaceSourceIU, info);
}
// Include all source IUs in the map.
workspaceIUInfos.putAll(workspaceSourceIUInfos);
}
};
provisioningContext.setProperty(ProvisioningContext.FOLLOW_REPOSITORY_REFERENCES, Boolean.FALSE.toString());
provisioningContext.setProperty(FOLLOW_ARTIFACT_REPOSITORY_REFERENCES, Boolean.FALSE.toString());
return provisioningContext;
}
@Override
public boolean handleProvisioningPlan(ResolutionInfo info) throws CoreException
{
provisioningPlan = info.getProvisioningPlan();
artificialRoot = info.getArtificialRoot();
metadataRepositories = info.getMetadataRepositories();
return true;
}
@Override
public IPhaseSet getPhaseSet(ProfileTransaction transaction)
{
List<Phase> phases = new ArrayList<Phase>(4);
phases.add(new Collect(100));
phases.add(new Property(1));
phases.add(new Uninstall(50, true)
{
@Override
protected java.util.List<ProvisioningAction> getActions(InstallableUnitOperand currentOperand)
{
// If a product IU is provisioned, it pulls in tooling fragments that try to work with the non-existing artifacts of our workspace-based IUs.
// So we'd remove them for the purpose of this phase.
IInstallableUnit first = currentOperand.first();
if (first != null)
{
if ("true".equals(first.getProperty(WorkspaceIUAnalyzer.IU_PROPERTY_WORKSPACE)) && first instanceof ResolvedInstallableUnit)
{
return super.getActions(new InstallableUnitOperand(
new ResolvedInstallableUnit((IInstallableUnit)((ResolvedInstallableUnit)first).getMember(ResolvedInstallableUnit.MEMBER_ORIGINAL)), null));
}
}
return super.getActions(currentOperand);
}
});
phases.add(new Install(50)
{
@Override
protected java.util.List<ProvisioningAction> getActions(InstallableUnitOperand currentOperand)
{
// If a product IU is provisioned, it pulls in tooling fragments that try to work with the non-existing artifacts of our workspace-based IUs.
// So we'd remove them for the purpose of this phase.
IInstallableUnit second = currentOperand.second();
if (second != null)
{
if ("true".equals(second.getProperty(WorkspaceIUAnalyzer.IU_PROPERTY_WORKSPACE)) && second instanceof ResolvedInstallableUnit)
{
return super.getActions(new InstallableUnitOperand(null,
new ResolvedInstallableUnit((IInstallableUnit)((ResolvedInstallableUnit)second).getMember(ResolvedInstallableUnit.MEMBER_ORIGINAL))));
}
}
return super.getActions(currentOperand);
}
});
phases.add(new CollectNativesPhase(profile.getBundlePool(), 100));
return new PhaseSet(phases.toArray(new Phase[phases.size()]));
}
private static IInstallableUnit createPDETargetPlatformIU()
{
InstallableUnitDescription description = new InstallableUnitDescription();
description.setId(A_PDE_TARGET_PLATFORM_LOWER_CASE);
Version version = Version.createOSGi(1, 0, 0);
description.setVersion(version);
description.addProvidedCapabilities(
Collections.singleton(MetadataFactory.createProvidedCapability(A_PDE_TARGET_PLATFORM, "Cannot be installed into the IDE", version)));
description.setTouchpointType(org.eclipse.equinox.spi.p2.publisher.PublisherHelper.TOUCHPOINT_OSGI);
description.setArtifacts(new IArtifactKey[0]);
return MetadataFactory.createInstallableUnit(description);
}
/**
* @author Pascal Rapicault
*/
private static final class CollectNativesPhase extends InstallableUnitPhase
{
private static final String NATIVE_TYPE = "org.eclipse.equinox.p2.native"; //$NON-NLS-1$
private final BundlePool bundlePool;
public CollectNativesPhase(BundlePool bundlePool, int weight)
{
super(NATIVE_ARTIFACTS, weight);
this.bundlePool = bundlePool;
}
@Override
protected List<ProvisioningAction> getActions(InstallableUnitOperand operand)
{
IInstallableUnit installableUnit = operand.second();
if (installableUnit != null && installableUnit.getTouchpointType().getId().equals(NATIVE_TYPE))
{
List<ProvisioningAction> list = new ArrayList<ProvisioningAction>(1);
list.add(new CollectNativesAction(bundlePool));
return list;
}
return null;
}
@Override
protected IStatus initializePhase(IProgressMonitor monitor, IProfile profile, Map<String, Object> parameters)
{
parameters.put(NATIVE_ARTIFACTS, new ArrayList<Object>());
parameters.put(PARM_PROFILE, profile);
return null;
}
@Override
protected IStatus completePhase(IProgressMonitor monitor, IProfile profile, Map<String, Object> parameters)
{
@SuppressWarnings("unchecked")
List<IArtifactRequest> artifactRequests = (List<IArtifactRequest>)parameters.get(NATIVE_ARTIFACTS);
ProvisioningContext context = (ProvisioningContext)parameters.get(PARM_CONTEXT);
IProvisioningAgent agent = (IProvisioningAgent)parameters.get(PARM_AGENT);
DownloadManager downloadManager = new DownloadManager(context, agent);
for (Iterator<IArtifactRequest> it = artifactRequests.iterator(); it.hasNext();)
{
downloadManager.add(it.next());
}
return downloadManager.start(monitor);
}
}
/**
* @author Pascal Rapicault
*/
private static final class CollectNativesAction extends ProvisioningAction
{
private static final String PARM_OPERAND = "operand"; //$NON-NLS-1$
private final BundlePool bundlePool;
public CollectNativesAction(BundlePool bundlePool)
{
this.bundlePool = bundlePool;
}
@Override
public IStatus execute(Map<String, Object> parameters)
{
InstallableUnitOperand operand = (InstallableUnitOperand)parameters.get(PARM_OPERAND);
IInstallableUnit installableUnit = operand.second();
if (installableUnit == null)
{
return Status.OK_STATUS;
}
try
{
Collection<?> toDownload = installableUnit.getArtifacts();
if (toDownload == null)
{
return Status.OK_STATUS;
}
@SuppressWarnings("unchecked")
List<IArtifactRequest> artifactRequests = (List<IArtifactRequest>)parameters.get(NATIVE_ARTIFACTS);
IArtifactRepositoryManager manager = bundlePool.getAgent().getArtifactRepositoryManager();
IFileArtifactRepository fileArtifactRepository = bundlePool.getFileArtifactRepository();
for (Iterator<?> it = toDownload.iterator(); it.hasNext();)
{
IArtifactKey keyToDownload = (IArtifactKey)it.next();
IArtifactRequest request = manager.createMirrorRequest(keyToDownload, fileArtifactRepository, null, null);
artifactRequests.add(request);
}
}
catch (Exception ex)
{
return TargletsCorePlugin.INSTANCE.getStatus(ex);
}
return Status.OK_STATUS;
}
@Override
public IStatus undo(Map<String, Object> parameters)
{
// Nothing to do for now.
return Status.OK_STATUS;
}
}
}
/**
* @author Eike Stepper
*/
public static class Persistence implements ITargetLocationFactory
{
private static final Map<Object, Object> XML_OPTIONS;
private static final BasicExtendedMetaData EXTENDED_META_DATA = new BasicExtendedMetaData()
{
@Override
public EStructuralFeature getElement(EClass eClass, String namespace, String name)
{
EStructuralFeature eStructuralFeature = super.getElement(eClass, namespace, name);
if (eStructuralFeature == null)
{
eStructuralFeature = super.getElement(eClass, namespace, name.substring(0, name.length() - 1));
}
if (eStructuralFeature == null)
{
eStructuralFeature = eClass.getEStructuralFeature(name);
}
return eStructuralFeature;
}
};
private static final EStructuralFeature LOCATION_TYPE_FEATURE = EXTENDED_META_DATA.demandFeature(null, "type", false);
private static final EStructuralFeature LOCATION_ID_FEATURE = EXTENDED_META_DATA.demandFeature(null, "id", false);
private static final EStructuralFeature LOCATION_FEATURE = EXTENDED_META_DATA.demandFeature(null, "location", true);
private static final EStructuralFeature TARGLET_FEATURE = EXTENDED_META_DATA.demandFeature(null, "targlet", true);
private static final EClass DOCUMENT_ROOT_CLASS = LOCATION_FEATURE.getEContainingClass();
static
{
XMLOptions xmlOptions = new XMLOptionsImpl();
xmlOptions.setProcessAnyXML(true);
xmlOptions.setProcessSchemaLocations(true);
Map<Object, Object> options = new HashMap<Object, Object>();
options.put(XMLResource.OPTION_DECLARE_XML, Boolean.FALSE);
options.put(XMLResource.OPTION_EXTENDED_META_DATA, EXTENDED_META_DATA);
options.put(XMLResource.OPTION_LAX_FEATURE_PROCESSING, Boolean.TRUE);
options.put(XMLResource.OPTION_XML_OPTIONS, xmlOptions);
XML_OPTIONS = Collections.unmodifiableMap(options);
}
public ITargletContainer getTargetLocation(String type, String serializedXML) throws CoreException
{
if (TYPE.equals(type))
{
return fromXML(serializedXML);
}
return null;
}
public static ITargletContainer fromXML(String xml) throws CoreException
{
try
{
XMLResource resource = new XMLResourceImpl();
resource.load(new InputSource(new StringReader(xml)), XML_OPTIONS);
EObject documentRoot = resource.getContents().get(0);
AnyType location = (AnyType)documentRoot.eContents().get(0);
String id = (String)location.eGet(LOCATION_ID_FEATURE);
EList<Targlet> targlets = new BasicEList<Targlet>();
for (EObject eObject : location.eContents())
{
targlets.add((Targlet)eObject);
}
return new TargletContainer(id, targlets);
}
catch (Exception ex)
{
TargletsCorePlugin.INSTANCE.coreException(ex);
}
return null;
}
public static Writer toXML(String id, List<Targlet> targlets) throws Exception
{
AnyType location = XMLTypeFactory.eINSTANCE.createAnyType();
location.eSet(LOCATION_ID_FEATURE, id);
location.eSet(LOCATION_TYPE_FEATURE, TYPE);
EObject documentRoot = EcoreUtil.create(DOCUMENT_ROOT_CLASS);
documentRoot.eSet(LOCATION_FEATURE, location);
FeatureMap targletFeatureMap = location.getAny();
FeatureMapUtil.addText(targletFeatureMap, "\n ");
EList<Targlet> copy = TargletFactory.eINSTANCE.copyTarglets(targlets);
for (Targlet targlet : copy)
{
targletFeatureMap.add(TARGLET_FEATURE, targlet);
}
StringWriter writer = new StringWriter();
XMLResource resource = new XMLResourceImpl();
resource.getContents().add(documentRoot);
resource.save(writer, XML_OPTIONS);
return writer;
}
}
/**
* @author Ed Merks
*/
private static class IU
{
private final String id;
private final Version version;
public IU(IInstallableUnit iu)
{
this(iu.getId(), iu.getVersion());
}
public IU(String id, Version version)
{
this.id = id;
this.version = P2Factory.eINSTANCE.createVersionRange(version, VersionSegment.MICRO).getMinimum();
}
public String getId()
{
return id;
}
public Version getVersion()
{
return version;
}
@Override
public int hashCode()
{
return id.hashCode();
}
@Override
public boolean equals(Object obj)
{
if (obj instanceof IU)
{
IU iu = (IU)obj;
if (id.equals(iu.getId()))
{
Version version = iu.getVersion();
if (this.version.equals(version) || Version.emptyVersion.equals(version) || Version.emptyVersion.equals(this.version))
{
return true;
}
}
}
return false;
}
}
}