blob: 30e1908327b956c450de0b7e7f3046fbcdc4ced4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2016 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
* Danail Nachev - ProSyst - bug 218625
* Rob Harrop - SpringSource Inc. (bug 247522)
*******************************************************************************/
package org.eclipse.osgi.internal.resolver;
import java.util.*;
import org.eclipse.osgi.internal.framework.EquinoxContainer;
import org.eclipse.osgi.service.resolver.*;
import org.osgi.framework.Constants;
import org.osgi.framework.wiring.BundleRevision;
public class ImportPackageSpecificationImpl extends VersionConstraintImpl implements ImportPackageSpecification {
private String resolution = ImportPackageSpecification.RESOLUTION_STATIC; // the default is static
private String symbolicName;
private VersionRange bundleVersionRange;
private Map<String, Object> attributes;
private Map<String, String> arbitraryDirectives;
public Map<String, Object> getDirectives() {
synchronized (this.monitor) {
Map<String, Object> result = new HashMap<>(5);
if (resolution != null)
result.put(Constants.RESOLUTION_DIRECTIVE, resolution);
return result;
}
}
public Object getDirective(String key) {
synchronized (this.monitor) {
if (key.equals(Constants.RESOLUTION_DIRECTIVE))
return resolution;
return null;
}
}
Object setDirective(String key, Object value) {
synchronized (this.monitor) {
if (key.equals(Constants.RESOLUTION_DIRECTIVE))
return resolution = (String) value;
return null;
}
}
void setDirectives(Map<String, ?> directives) {
synchronized (this.monitor) {
if (directives == null)
return;
resolution = (String) directives.get(Constants.RESOLUTION_DIRECTIVE);
}
}
@SuppressWarnings("unchecked")
void setArbitraryDirectives(Map<String, ?> directives) {
synchronized (this.monitor) {
this.arbitraryDirectives = (Map<String, String>) directives;
}
}
Map<String, String> getArbitraryDirectives() {
synchronized (this.monitor) {
return arbitraryDirectives;
}
}
public String getBundleSymbolicName() {
synchronized (this.monitor) {
if (Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(symbolicName)) {
StateImpl state = (StateImpl) getBundle().getContainingState();
return state == null ? EquinoxContainer.NAME : state.getSystemBundle();
}
return symbolicName;
}
}
public VersionRange getBundleVersionRange() {
synchronized (this.monitor) {
if (bundleVersionRange == null)
return VersionRange.emptyRange;
return bundleVersionRange;
}
}
public Map<String, Object> getAttributes() {
synchronized (this.monitor) {
return attributes;
}
}
@Override
public boolean isSatisfiedBy(BaseDescription supplier) {
return isSatisfiedBy(supplier, true);
}
public boolean isSatisfiedBy(BaseDescription supplier, boolean checkEE) {
if (!(supplier instanceof ExportPackageDescription))
return false;
ExportPackageDescriptionImpl pkgDes = (ExportPackageDescriptionImpl) supplier;
// If we are in strict mode, check to see if the export specifies friends.
// If it does, are we one of the friends
String[] friends = (String[]) pkgDes.getDirective(StateImpl.FRIENDS_DIRECTIVE);
Boolean internal = (Boolean) pkgDes.getDirective(StateImpl.INTERNAL_DIRECTIVE);
if (internal.booleanValue() || friends != null) {
StateImpl state = (StateImpl) getBundle().getContainingState();
boolean strict = state == null ? false : state.inStrictMode();
if (strict) {
if (internal.booleanValue())
return false;
boolean found = false;
if (friends != null && getBundle().getSymbolicName() != null)
for (String friend : friends) {
if (getBundle().getSymbolicName().equals(friend)) {
found = true;
}
}
if (!found)
return false;
}
}
String exporterSymbolicName = getBundleSymbolicName();
if (exporterSymbolicName != null) {
BundleDescription exporter = pkgDes.getExporter();
if (!exporterSymbolicName.equals(exporter.getSymbolicName()))
return false;
if (getBundleVersionRange() != null && !getBundleVersionRange().isIncluded(exporter.getVersion()))
return false;
}
String name = getName();
// shortcut '*'
// NOTE: wildcards are supported only in cases where this is a dynamic import
if (!"*".equals(name) && !(name.endsWith(".*") && pkgDes.getName().startsWith(name.substring(0, name.length() - 1))) && !pkgDes.getName().equals(name)) //$NON-NLS-1$ //$NON-NLS-2$
return false;
if (getVersionRange() != null && !getVersionRange().isIncluded(pkgDes.getVersion()))
return false;
Map<String, ?> importAttrs = getAttributes();
if (importAttrs != null) {
Map<String, ?> exportAttrs = pkgDes.getAttributes();
if (exportAttrs == null)
return false;
for (String importKey : importAttrs.keySet()) {
Object importValue = importAttrs.get(importKey);
Object exportValue = exportAttrs.get(importKey);
if (exportValue == null || !importValue.equals(exportValue))
return false;
}
}
String[] mandatory = (String[]) pkgDes.getDirective(Constants.MANDATORY_DIRECTIVE);
if (!hasMandatoryAttributes(mandatory))
return false;
// finally check the ee index
if (!checkEE)
return true;
if (((BundleDescriptionImpl) getBundle()).getEquinoxEE() < 0)
return true;
int eeIndex = ((Integer) pkgDes.getDirective(ExportPackageDescriptionImpl.EQUINOX_EE)).intValue();
return eeIndex < 0 || eeIndex == ((BundleDescriptionImpl) getBundle()).getEquinoxEE();
}
@Override
protected boolean hasMandatoryAttributes(String[] checkMandatory) {
if (checkMandatory != null) {
Map<String, ?> importAttrs = getAttributes();
for (String mandatory : checkMandatory) {
if (Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE.equals(mandatory)) {
if (getBundleSymbolicName() == null)
return false;
} else if (Constants.BUNDLE_VERSION_ATTRIBUTE.equals(mandatory)) {
if (bundleVersionRange == null)
return false;
} else if (Constants.PACKAGE_SPECIFICATION_VERSION.equals(mandatory) || Constants.VERSION_ATTRIBUTE.equals(mandatory)) {
if (getVersionRange() == null)
return false;
} else { // arbitrary attribute
if (importAttrs == null)
return false;
if (importAttrs.get(mandatory) == null) {
return false;
}
}
}
}
return true;
}
protected void setBundleSymbolicName(String symbolicName) {
synchronized (this.monitor) {
this.symbolicName = symbolicName;
}
}
protected void setBundleVersionRange(VersionRange bundleVersionRange) {
synchronized (this.monitor) {
this.bundleVersionRange = bundleVersionRange;
}
}
@SuppressWarnings("unchecked")
protected void setAttributes(Map<String, ?> attributes) {
synchronized (this.monitor) {
this.attributes = (Map<String, Object>) attributes;
}
}
@Override
public String toString() {
return "Import-Package: " + getName() + "; version=\"" + getVersionRange() + "\""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
@Override
protected Map<String, String> getInternalDirectives() {
synchronized (this.monitor) {
Map<String, String> result = new HashMap<>(5);
if (arbitraryDirectives != null)
result.putAll(arbitraryDirectives);
if (resolution != null) {
if (ImportPackageSpecification.RESOLUTION_STATIC.equals(resolution))
result.put(Constants.RESOLUTION_DIRECTIVE, Constants.RESOLUTION_MANDATORY);
else
result.put(Constants.RESOLUTION_DIRECTIVE, resolution);
}
result.put(Constants.FILTER_DIRECTIVE, createFilterDirective());
return result;
}
}
private String createFilterDirective() {
StringBuffer filter = new StringBuffer();
filter.append("(&"); //$NON-NLS-1$
synchronized (this.monitor) {
addFilterAttribute(filter, BundleRevision.PACKAGE_NAMESPACE, getName(), false);
VersionRange range = getVersionRange();
if (range != null && range != VersionRange.emptyRange)
addFilterAttribute(filter, Constants.VERSION_ATTRIBUTE, range);
if (symbolicName != null)
addFilterAttribute(filter, Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, symbolicName);
if (bundleVersionRange != null)
addFilterAttribute(filter, Constants.BUNDLE_VERSION_ATTRIBUTE, bundleVersionRange);
if (attributes != null)
addFilterAttributes(filter, attributes);
}
filter.append(')');
return filter.toString();
}
@Override
protected Map<String, Object> getInteralAttributes() {
return Collections.<String, Object> emptyMap();
}
@Override
protected String getInternalNameSpace() {
return BundleRevision.PACKAGE_NAMESPACE;
}
}