blob: 7d49b306de2d3bdf45a7fb55a997f58e6fb928e9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2018 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Genuitec, LLC - added license support
*******************************************************************************/
package org.eclipse.equinox.internal.p2.metadata;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils;
import org.eclipse.equinox.internal.p2.core.helpers.OrderedProperties;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
import org.eclipse.equinox.p2.metadata.ICopyright;
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.ITouchpointType;
import org.eclipse.equinox.p2.metadata.IUpdateDescriptor;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.metadata.expression.ExpressionUtil;
import org.eclipse.equinox.p2.metadata.expression.IExpression;
import org.eclipse.equinox.p2.metadata.expression.IExpressionFactory;
import org.eclipse.equinox.p2.metadata.expression.IFilterExpression;
import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
import org.eclipse.equinox.p2.metadata.expression.IMemberProvider;
public class InstallableUnit implements IInstallableUnit, IMemberProvider {
@SuppressWarnings("serial")
private static final Map<IFilterExpression, IMatchExpression<IInstallableUnit>> filterCache = new LinkedHashMap<>() {
@Override
public boolean removeEldestEntry(Map.Entry<IFilterExpression, IMatchExpression<IInstallableUnit>> expr) {
return size() > 64;
}
};
private static final OrderedProperties NO_PROPERTIES = new OrderedProperties();
private static final IProvidedCapability[] NO_PROVIDES = new IProvidedCapability[0];
private static final IRequirement[] NO_REQUIRES = new IRequirement[0];
private static final IArtifactKey[] NO_ARTIFACTS = new IArtifactKey[0];
private static final ITouchpointData[] NO_TOUCHPOINT_DATA = new ITouchpointData[0];
private static final ILicense[] NO_LICENSE = new ILicense[0];
private static final IExpression filterWrap;
public static final String MEMBER_PROVIDED_CAPABILITIES = "providedCapabilities"; //$NON-NLS-1$
public static final String MEMBER_ID = "id"; //$NON-NLS-1$
public static final String MEMBER_VERSION = "version"; //$NON-NLS-1$
public static final String MEMBER_PROPERTIES = "properties"; //$NON-NLS-1$
public static final String MEMBER_FILTER = "filter"; //$NON-NLS-1$
public static final String MEMBER_ARTIFACTS = "artifacts"; //$NON-NLS-1$
public static final String MEMBER_REQUIREMENTS = "requirements"; //$NON-NLS-1$
public static final String MEMBER_LICENSES = "licenses"; //$NON-NLS-1$
public static final String MEMBER_COPYRIGHT = "copyright"; //$NON-NLS-1$
public static final String MEMBER_TOUCHPOINT_DATA = "touchpointData"; //$NON-NLS-1$
public static final String MEMBER_TOUCHPOINT_TYPE = "touchpointType"; //$NON-NLS-1$
public static final String MEMBER_UPDATE_DESCRIPTOR = "updateDescriptor"; //$NON-NLS-1$
public static final String MEMBER_SINGLETON = "singleton"; //$NON-NLS-1$
static {
IExpressionFactory factory = ExpressionUtil.getFactory();
filterWrap = factory.matches(factory.member(factory.thisVariable(), MEMBER_PROPERTIES),
factory.indexedParameter(0));
}
private IArtifactKey[] artifacts = NO_ARTIFACTS;
private IMatchExpression<IInstallableUnit> filter;
private String id;
private OrderedProperties properties;
private OrderedProperties localizedProperties;
IProvidedCapability[] providedCapabilities = NO_PROVIDES;
private IRequirement[] requires = NO_REQUIRES;
private IRequirement[] metaRequires = NO_REQUIRES;
private boolean singleton;
private ITouchpointData[] touchpointData = NO_TOUCHPOINT_DATA;
private ITouchpointType touchpointType;
private Version version = Version.emptyVersion;
private IUpdateDescriptor updateInfo;
private ILicense[] licenses = NO_LICENSE;
private ICopyright copyright;
public static final String MEMBER_TRANSLATED_PROPERTIES = "translatedProperties"; //$NON-NLS-1$
public static final String MEMBER_PROFILE_PROPERTIES = "profileProperties"; //$NON-NLS-1$
public InstallableUnit() {
super();
}
public void addTouchpointData(ITouchpointData newData) {
int tl = touchpointData.length;
if (tl == 0)
touchpointData = new ITouchpointData[] { newData };
else {
ITouchpointData[] newDatas = new ITouchpointData[tl + 1];
System.arraycopy(touchpointData, 0, newDatas, 0, tl);
newDatas[tl] = newData;
touchpointData = newDatas;
}
}
@Override
public int compareTo(IInstallableUnit other) {
int cmp = getId().compareTo(other.getId());
if (cmp == 0)
cmp = getVersion().compareTo(other.getVersion());
return cmp;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof IInstallableUnit))
return false;
final IInstallableUnit other = (IInstallableUnit) obj;
if (id == null) {
if (other.getId() != null)
return false;
} else if (!id.equals(other.getId()))
return false;
if (getVersion() == null) {
if (other.getVersion() != null)
return false;
} else if (!getVersion().equals(other.getVersion()))
return false;
return true;
}
@Override
public Collection<IArtifactKey> getArtifacts() {
return CollectionUtils.unmodifiableList(artifacts);
}
@Override
public IMatchExpression<IInstallableUnit> getFilter() {
return filter;
}
@Override
public Collection<IInstallableUnitFragment> getFragments() {
return Collections.emptyList();
}
@Override
public String getId() {
return id;
}
/**
* Get an <i>unmodifiable copy</i> of the properties associated with the
* installable unit.
*
* @return an <i>unmodifiable copy</i> of the IU properties.
*/
@Override
public Map<String, String> getProperties() {
return OrderedProperties.unmodifiableProperties(properties());
}
/*
* Helper method to cache localized properties
*/
public String getLocalizedProperty(String key) {
String result = null;
if (localizedProperties != null)
result = localizedProperties.getProperty(key);
return result;
}
@Override
public String getProperty(String key) {
return properties().getProperty(key);
}
@Override
public Collection<IProvidedCapability> getProvidedCapabilities() {
return CollectionUtils.unmodifiableList(providedCapabilities);
}
@Override
public String getProperty(String key, String locale) {
return TranslationSupport.getInstance().getIUProperty(this, key, locale);
}
@Override
public List<IRequirement> getRequirements() {
return CollectionUtils.unmodifiableList(requires);
}
@Override
public Collection<ITouchpointData> getTouchpointData() {
return CollectionUtils.unmodifiableList(touchpointData);
}
@Override
public ITouchpointType getTouchpointType() {
return touchpointType != null ? touchpointType : ITouchpointType.NONE;
}
@Override
public Version getVersion() {
return version;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((getVersion() == null) ? 0 : getVersion().hashCode());
return result;
}
@Override
public boolean isResolved() {
return false;
}
@Override
public boolean isSingleton() {
return singleton;
}
private OrderedProperties properties() {
return (properties != null ? properties : NO_PROPERTIES);
}
public void setArtifacts(IArtifactKey[] value) {
if (value == null || value.length == 0)
artifacts = NO_ARTIFACTS;
else
artifacts = value;
}
public void setCapabilities(IProvidedCapability[] newCapabilities) {
if (newCapabilities == null || newCapabilities.length == 0)
providedCapabilities = NO_PROVIDES;
else
providedCapabilities = newCapabilities;
}
public void setFilter(IMatchExpression<IInstallableUnit> filter) {
this.filter = filter;
}
public void setFilter(String filter) {
setFilter(parseFilter(filter));
}
public void setId(String id) {
this.id = id;
}
public static IMatchExpression<IInstallableUnit> parseFilter(String filterStr) {
IFilterExpression filter = ExpressionUtil.parseLDAP(filterStr);
if (filter == null)
return null;
synchronized (filterCache) {
IMatchExpression<IInstallableUnit> matchExpr = filterCache.get(filter);
if (matchExpr != null)
return matchExpr;
matchExpr = ExpressionUtil.getFactory().matchExpression(filterWrap, filter);
filterCache.put(filter, matchExpr);
return matchExpr;
}
}
/*
* Helper method to cache localized properties
*/
public String setLocalizedProperty(String key, String value) {
if (localizedProperties == null)
localizedProperties = new OrderedProperties();
return localizedProperties.put(key, value);
}
public String setProperty(String key, String value) {
if (value == null)
return (properties != null ? (String) properties.remove(key) : null);
if (properties == null)
properties = new OrderedProperties();
return (String) properties.setProperty(key, value);
}
public void setRequiredCapabilities(IRequirement[] capabilities) {
if (capabilities.length == 0) {
this.requires = NO_REQUIRES;
} else {
// copy array for safety
this.requires = capabilities.clone();
}
}
public void setSingleton(boolean singleton) {
this.singleton = singleton;
}
public void setTouchpointType(ITouchpointType type) {
this.touchpointType = (type != ITouchpointType.NONE ? type : null);
}
public void setVersion(Version newVersion) {
this.version = (newVersion != null ? newVersion : Version.emptyVersion);
}
@Override
public String toString() {
return id + ' ' + getVersion();
}
@Override
public IInstallableUnit unresolved() {
return this;
}
@Override
public IUpdateDescriptor getUpdateDescriptor() {
return updateInfo;
}
public void setUpdateDescriptor(IUpdateDescriptor updateInfo) {
this.updateInfo = updateInfo;
}
public void setLicenses(ILicense[] license) {
this.licenses = license == null ? NO_LICENSE : license;
}
@Override
public Collection<ILicense> getLicenses() {
return CollectionUtils.unmodifiableList(licenses);
}
@Override
public Collection<ILicense> getLicenses(String locale) {
return CollectionUtils.unmodifiableList(TranslationSupport.getInstance().getLicenses(this, locale));
}
public void setCopyright(ICopyright copyright) {
this.copyright = copyright;
}
@Override
public ICopyright getCopyright() {
return copyright;
}
@Override
public ICopyright getCopyright(String locale) {
return TranslationSupport.getInstance().getCopyright(this, locale);
}
@Override
public boolean satisfies(IRequirement candidate) {
return candidate.isMatch(this);
}
@Override
public Collection<IRequirement> getMetaRequirements() {
return CollectionUtils.unmodifiableList(metaRequires);
}
public void setMetaRequiredCapabilities(IRequirement[] metaReqs) {
if (metaReqs.length == 0) {
this.metaRequires = NO_REQUIRES;
} else {
// copy array for safety
this.metaRequires = metaReqs.clone();
}
}
@Override
public Object getMember(String memberName) {
// It is OK to use identity comparisons here since
// a) All constant valued strings are always interned
// b) The Member constructor always interns the name
//
if (MEMBER_PROVIDED_CAPABILITIES == memberName)
return providedCapabilities;
if (MEMBER_ID == memberName)
return id;
if (MEMBER_VERSION == memberName)
return version;
if (MEMBER_PROPERTIES == memberName)
return properties;
if (MEMBER_FILTER == memberName)
return filter;
if (MEMBER_ARTIFACTS == memberName)
return artifacts;
if (MEMBER_REQUIREMENTS == memberName)
return requires;
if (MEMBER_LICENSES == memberName)
return licenses;
if (MEMBER_COPYRIGHT == memberName)
return copyright;
if (MEMBER_TOUCHPOINT_DATA == memberName)
return touchpointData;
if (MEMBER_TOUCHPOINT_TYPE == memberName)
return touchpointType;
if (MEMBER_UPDATE_DESCRIPTOR == memberName)
return updateInfo;
if (MEMBER_SINGLETON == memberName)
return Boolean.valueOf(singleton);
throw new IllegalArgumentException("No such member: " + memberName); //$NON-NLS-1$
}
public static IInstallableUnit contextIU(String ws, String os, String arch) {
InstallableUnit ctxIU = new InstallableUnit();
ctxIU.setId("org.eclipse.equinox.p2.context.iu"); //$NON-NLS-1$
ctxIU.setProperty("osgi.ws", ws); //$NON-NLS-1$
ctxIU.setProperty("osgi.os", os); //$NON-NLS-1$
ctxIU.setProperty("osgi.arch", arch); //$NON-NLS-1$
return ctxIU;
}
public static IInstallableUnit contextIU(Map<String, String> environment) {
InstallableUnit ctxIU = new InstallableUnit();
ctxIU.setId("org.eclipse.equinox.p2.context.iu"); //$NON-NLS-1$
for (Map.Entry<String, String> entry : environment.entrySet())
ctxIU.setProperty(entry.getKey(), entry.getValue());
return ctxIU;
}
}