blob: 83e08cc48d00573a54cb6a329192ae037a8e9453 [file] [log] [blame]
/*
* Copyright (c) 2014 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.p2.internal.core;
import org.eclipse.oomph.p2.P2Exception;
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.Agent;
import org.eclipse.oomph.p2.core.AgentManager;
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.util.IOUtil;
import org.eclipse.oomph.util.StringUtil;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.BasicExtendedMetaData;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.equinox.internal.p2.engine.SimpleProfileRegistry;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.engine.IProfile;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.VersionRange;
import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.IRepositoryManager;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import org.xml.sax.InputSource;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Eike Stepper
*/
@SuppressWarnings("restriction")
public class ProfileImpl extends AgentManagerElementImpl implements Profile, PersistentMap.ExtraInfoProvider
{
private static final Map<Object, Object> XML_OPTIONS;
static
{
Map<Object, Object> options = new HashMap<Object, Object>();
options.put(XMLResource.OPTION_DECLARE_XML, Boolean.FALSE);
options.put(XMLResource.OPTION_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;
}
@Override
protected boolean isFeatureKindSpecific()
{
return false;
}
});
XML_OPTIONS = Collections.unmodifiableMap(options);
}
private final Agent agent;
private final BundlePool bundlePool;
private final String id;
private final String type;
private final File installFolder;
private final File referencer;
private IProfile delegate;
private ProfileDefinition definition;
public ProfileImpl(Agent agent, BundlePool bundlePool, String id, String type, File installFolder, File referencer)
{
this.agent = agent;
this.bundlePool = bundlePool;
this.id = id;
this.type = type;
this.installFolder = installFolder;
this.referencer = referencer;
}
@Override
public String getElementType()
{
return "profile";
}
public AgentManager getAgentManager()
{
return agent.getAgentManager();
}
public Agent getAgent()
{
return agent;
}
public BundlePool getBundlePool()
{
return bundlePool;
}
public String getProfileId()
{
return id;
}
public String getType()
{
return type;
}
public File getLocation()
{
File engineLocation = new File(agent.getLocation(), AgentImpl.ENGINE_PATH);
File registryLocation = new File(engineLocation, SimpleProfileRegistry.DEFAULT_STORAGE_DIR);
return new File(registryLocation, id + ".profile");
}
public File getInstallFolder()
{
return installFolder;
}
public File getReferencer()
{
return referencer;
}
public String getExtraInfo()
{
List<String> tokens = new ArrayList<String>();
tokens.add(type);
tokens.add(bundlePool != null ? bundlePool.getLocation().getAbsolutePath() : "");
tokens.add(installFolder != null ? installFolder.getAbsolutePath() : "");
tokens.add(referencer != null ? referencer.getAbsolutePath() : "");
return StringUtil.implode(tokens, '|');
}
public synchronized IProfile getDelegate()
{
return getDelegate(true);
}
public synchronized IProfile getDelegate(boolean loadOnDemand)
{
if (delegate == null)
{
if (loadOnDemand)
{
delegate = getAgent().getProfileRegistry().getProfile(id);
if (delegate == null)
{
throw new P2Exception("Profile does not exist: " + id);
}
}
}
return delegate;
}
public void setDelegate(IProfile delegate)
{
this.delegate = delegate;
}
public synchronized ProfileDefinition getDefinition()
{
if (definition == null)
{
String xml = getDelegate().getProperty(PROP_PROFILE_DEFINITION);
if (xml == null)
{
// TODO This is also called via ProfileTransactionImpl() for new profiles. Should it be empty then?
definition = definitionFromRootIUs(this, VersionSegment.MINOR);
}
else
{
definition = definitionFromXML(xml);
}
}
return definition;
}
public void setDefinition(ProfileDefinition definition)
{
this.definition = definition;
}
public boolean isValid()
{
return getLocation().isDirectory();
}
public boolean isCurrent()
{
return agent.getCurrentProfile() == this;
}
public boolean isUsed()
{
File referencer = this.referencer;
if (referencer == null && "Targlet".equals(type))
{
String workspace = getProperty("targlet.container.workspace");
if (workspace != null)
{
referencer = new File(workspace, ".metadata/.plugins/org.eclipse.oomph.targlets.core/targlet-profiles.txt");
}
}
if (referencer != null)
{
if (!referencer.exists())
{
return false;
}
if (referencer.isFile())
{
List<String> lines = IOUtil.readLines(referencer, null);
if (!lines.contains(id))
{
return false;
}
}
return true;
}
return installFolder == null || installFolder.isDirectory();
}
@Override
protected void doDelete()
{
((AgentImpl)agent).deleteProfile(this);
}
public ProfileTransaction change()
{
return new ProfileTransactionImpl(this);
}
public IQueryResult<IInstallableUnit> query(IQuery<IInstallableUnit> query, IProgressMonitor monitor)
{
return getDelegate().query(query, monitor);
}
public IProvisioningAgent getProvisioningAgent()
{
return getDelegate().getProvisioningAgent();
}
public String getProperty(String key)
{
return getDelegate().getProperty(key);
}
public String getInstallableUnitProperty(IInstallableUnit iu, String key)
{
return getDelegate().getInstallableUnitProperty(iu, key);
}
public Map<String, String> getProperties()
{
return getDelegate().getProperties();
}
public Map<String, String> getInstallableUnitProperties(IInstallableUnit iu)
{
return getDelegate().getInstallableUnitProperties(iu);
}
public long getTimestamp()
{
return getDelegate().getTimestamp();
}
public IQueryResult<IInstallableUnit> available(IQuery<IInstallableUnit> query, IProgressMonitor monitor)
{
return getDelegate().available(query, monitor);
}
@Override
public String toString()
{
return id;
}
public static String definitionToXML(ProfileDefinition definition)
{
try
{
StringWriter writer = new StringWriter();
XMLResource resource = new XMLResourceImpl();
resource.getContents().add(definition);
resource.save(writer, XML_OPTIONS);
return writer.toString();
}
catch (IOException ex)
{
throw new P2Exception(ex);
}
}
public static ProfileDefinition definitionFromXML(String xml)
{
try
{
XMLResource resource = new XMLResourceImpl();
resource.load(new InputSource(new StringReader(xml)), XML_OPTIONS);
return (ProfileDefinition)resource.getContents().get(0);
}
catch (IOException ex)
{
throw new P2Exception(ex);
}
}
public static ProfileDefinition definitionFromRootIUs(Profile profile, VersionSegment compatibility)
{
ProfileDefinition definition = P2Factory.eINSTANCE.createProfileDefinition();
EList<Requirement> requirements = definition.getRequirements();
IQueryResult<IInstallableUnit> query = profile.query(QueryUtil.createIUAnyQuery(), null);
for (IInstallableUnit iu : P2Util.asIterable(query))
{
if ("true".equals(profile.getInstallableUnitProperty(iu, Profile.PROP_PROFILE_ROOT_IU)))
{
VersionSegment iuCompatibility = null;
String iuProperty = profile.getInstallableUnitProperty(iu, Profile.PROP_IU_COMPATIBILITY);
if (iuProperty != null)
{
iuCompatibility = VersionSegment.get(iuProperty);
}
if (iuCompatibility == null)
{
iuProperty = iu.getProperty(Profile.PROP_IU_COMPATIBILITY);
if (iuProperty != null)
{
iuCompatibility = VersionSegment.get(iuProperty);
}
}
if (iuCompatibility == null)
{
iuCompatibility = compatibility;
}
VersionRange versionRange = P2Factory.eINSTANCE.createVersionRange(iu.getVersion(), iuCompatibility);
Requirement requirement = P2Factory.eINSTANCE.createRequirement(iu.getId());
requirement.setVersionRange(versionRange);
requirements.add(requirement);
}
}
IMetadataRepositoryManager metadataRepositoryManager = profile.getAgent().getMetadataRepositoryManager();
java.net.URI[] knownRepositories = metadataRepositoryManager.getKnownRepositories(IRepositoryManager.REPOSITORIES_NON_SYSTEM);
if (knownRepositories.length > 0)
{
EList<Repository> repositories = definition.getRepositories();
for (java.net.URI knownRepository : knownRepositories)
{
if (metadataRepositoryManager.isEnabled(knownRepository))
{
if (URIUtil.isFileURI(knownRepository))
{
File file = URIUtil.toFile(knownRepository);
if (!file.isDirectory())
{
metadataRepositoryManager.setEnabled(knownRepository, false);
continue;
}
}
Repository repository = P2Factory.eINSTANCE.createRepository(knownRepository.toString());
repositories.add(repository);
}
}
}
return definition;
}
}