1 /******************************************************************************* 2 * Copyright (c) 2003, 2016 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Danail Nachev - ProSyst - bug 218625 14 * Rob Harrop - SpringSource Inc. (bug 247522) 15 *******************************************************************************/ 16 package org.eclipse.osgi.internal.resolver; 17 18 import java.util.*; 19 import org.eclipse.osgi.internal.framework.EquinoxContainer; 20 import org.eclipse.osgi.service.resolver.*; 21 import org.osgi.framework.Constants; 22 import org.osgi.framework.wiring.BundleRevision; 23 24 public class ImportPackageSpecificationImpl extends VersionConstraintImpl implements ImportPackageSpecification { 25 private String resolution = ImportPackageSpecification.RESOLUTION_STATIC; // the default is static 26 private String symbolicName; 27 private VersionRange bundleVersionRange; 28 private Map<String, Object> attributes; 29 private Map<String, String> arbitraryDirectives; 30 getDirectives()31 public Map<String, Object> getDirectives() { 32 synchronized (this.monitor) { 33 Map<String, Object> result = new HashMap<>(5); 34 if (resolution != null) 35 result.put(Constants.RESOLUTION_DIRECTIVE, resolution); 36 return result; 37 } 38 } 39 getDirective(String key)40 public Object getDirective(String key) { 41 synchronized (this.monitor) { 42 if (key.equals(Constants.RESOLUTION_DIRECTIVE)) 43 return resolution; 44 return null; 45 } 46 } 47 setDirective(String key, Object value)48 Object setDirective(String key, Object value) { 49 synchronized (this.monitor) { 50 if (key.equals(Constants.RESOLUTION_DIRECTIVE)) 51 return resolution = (String) value; 52 return null; 53 } 54 } 55 setDirectives(Map<String, ?> directives)56 void setDirectives(Map<String, ?> directives) { 57 synchronized (this.monitor) { 58 if (directives == null) 59 return; 60 resolution = (String) directives.get(Constants.RESOLUTION_DIRECTIVE); 61 } 62 } 63 64 @SuppressWarnings("unchecked") setArbitraryDirectives(Map<String, ?> directives)65 void setArbitraryDirectives(Map<String, ?> directives) { 66 synchronized (this.monitor) { 67 this.arbitraryDirectives = (Map<String, String>) directives; 68 } 69 } 70 getArbitraryDirectives()71 Map<String, String> getArbitraryDirectives() { 72 synchronized (this.monitor) { 73 return arbitraryDirectives; 74 } 75 } 76 getBundleSymbolicName()77 public String getBundleSymbolicName() { 78 synchronized (this.monitor) { 79 if (Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(symbolicName)) { 80 StateImpl state = (StateImpl) getBundle().getContainingState(); 81 return state == null ? EquinoxContainer.NAME : state.getSystemBundle(); 82 } 83 return symbolicName; 84 } 85 } 86 getBundleVersionRange()87 public VersionRange getBundleVersionRange() { 88 synchronized (this.monitor) { 89 if (bundleVersionRange == null) 90 return VersionRange.emptyRange; 91 return bundleVersionRange; 92 } 93 } 94 getAttributes()95 public Map<String, Object> getAttributes() { 96 synchronized (this.monitor) { 97 return attributes; 98 } 99 } 100 101 @Override isSatisfiedBy(BaseDescription supplier)102 public boolean isSatisfiedBy(BaseDescription supplier) { 103 return isSatisfiedBy(supplier, true); 104 } 105 isSatisfiedBy(BaseDescription supplier, boolean checkEE)106 public boolean isSatisfiedBy(BaseDescription supplier, boolean checkEE) { 107 if (!(supplier instanceof ExportPackageDescription)) 108 return false; 109 ExportPackageDescriptionImpl pkgDes = (ExportPackageDescriptionImpl) supplier; 110 111 // If we are in strict mode, check to see if the export specifies friends. 112 // If it does, are we one of the friends 113 String[] friends = (String[]) pkgDes.getDirective(StateImpl.FRIENDS_DIRECTIVE); 114 Boolean internal = (Boolean) pkgDes.getDirective(StateImpl.INTERNAL_DIRECTIVE); 115 if (internal.booleanValue() || friends != null) { 116 StateImpl state = (StateImpl) getBundle().getContainingState(); 117 boolean strict = state == null ? false : state.inStrictMode(); 118 if (strict) { 119 if (internal.booleanValue()) 120 return false; 121 boolean found = false; 122 if (friends != null && getBundle().getSymbolicName() != null) 123 for (String friend : friends) { 124 if (getBundle().getSymbolicName().equals(friend)) { 125 found = true; 126 } 127 } 128 if (!found) 129 return false; 130 } 131 } 132 String exporterSymbolicName = getBundleSymbolicName(); 133 if (exporterSymbolicName != null) { 134 BundleDescription exporter = pkgDes.getExporter(); 135 if (!exporterSymbolicName.equals(exporter.getSymbolicName())) 136 return false; 137 if (getBundleVersionRange() != null && !getBundleVersionRange().isIncluded(exporter.getVersion())) 138 return false; 139 } 140 141 String name = getName(); 142 // shortcut '*' 143 // NOTE: wildcards are supported only in cases where this is a dynamic import 144 if (!"*".equals(name) && !(name.endsWith(".*") && pkgDes.getName().startsWith(name.substring(0, name.length() - 1))) && !pkgDes.getName().equals(name)) //$NON-NLS-1$ //$NON-NLS-2$ 145 return false; 146 if (getVersionRange() != null && !getVersionRange().isIncluded(pkgDes.getVersion())) 147 return false; 148 149 Map<String, ?> importAttrs = getAttributes(); 150 if (importAttrs != null) { 151 Map<String, ?> exportAttrs = pkgDes.getAttributes(); 152 if (exportAttrs == null) 153 return false; 154 for (String importKey : importAttrs.keySet()) { 155 Object importValue = importAttrs.get(importKey); 156 Object exportValue = exportAttrs.get(importKey); 157 if (exportValue == null || !importValue.equals(exportValue)) 158 return false; 159 } 160 } 161 String[] mandatory = (String[]) pkgDes.getDirective(Constants.MANDATORY_DIRECTIVE); 162 if (!hasMandatoryAttributes(mandatory)) 163 return false; 164 // finally check the ee index 165 if (!checkEE) 166 return true; 167 if (((BundleDescriptionImpl) getBundle()).getEquinoxEE() < 0) 168 return true; 169 int eeIndex = ((Integer) pkgDes.getDirective(ExportPackageDescriptionImpl.EQUINOX_EE)).intValue(); 170 return eeIndex < 0 || eeIndex == ((BundleDescriptionImpl) getBundle()).getEquinoxEE(); 171 } 172 173 @Override hasMandatoryAttributes(String[] checkMandatory)174 protected boolean hasMandatoryAttributes(String[] checkMandatory) { 175 if (checkMandatory != null) { 176 Map<String, ?> importAttrs = getAttributes(); 177 for (String mandatory : checkMandatory) { 178 if (Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE.equals(mandatory)) { 179 if (getBundleSymbolicName() == null) 180 return false; 181 } else if (Constants.BUNDLE_VERSION_ATTRIBUTE.equals(mandatory)) { 182 if (bundleVersionRange == null) 183 return false; 184 } else if (Constants.PACKAGE_SPECIFICATION_VERSION.equals(mandatory) || Constants.VERSION_ATTRIBUTE.equals(mandatory)) { 185 if (getVersionRange() == null) 186 return false; 187 } else { // arbitrary attribute 188 if (importAttrs == null) 189 return false; 190 if (importAttrs.get(mandatory) == null) { 191 return false; 192 } 193 } 194 } 195 } 196 return true; 197 } 198 setBundleSymbolicName(String symbolicName)199 protected void setBundleSymbolicName(String symbolicName) { 200 synchronized (this.monitor) { 201 this.symbolicName = symbolicName; 202 } 203 } 204 setBundleVersionRange(VersionRange bundleVersionRange)205 protected void setBundleVersionRange(VersionRange bundleVersionRange) { 206 synchronized (this.monitor) { 207 this.bundleVersionRange = bundleVersionRange; 208 } 209 } 210 211 @SuppressWarnings("unchecked") setAttributes(Map<String, ?> attributes)212 protected void setAttributes(Map<String, ?> attributes) { 213 synchronized (this.monitor) { 214 this.attributes = (Map<String, Object>) attributes; 215 } 216 } 217 218 @Override toString()219 public String toString() { 220 return "Import-Package: " + getName() + "; version=\"" + getVersionRange() + "\""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 221 } 222 223 @Override getInternalDirectives()224 protected Map<String, String> getInternalDirectives() { 225 synchronized (this.monitor) { 226 Map<String, String> result = new HashMap<>(5); 227 if (arbitraryDirectives != null) 228 result.putAll(arbitraryDirectives); 229 if (resolution != null) { 230 if (ImportPackageSpecification.RESOLUTION_STATIC.equals(resolution)) 231 result.put(Constants.RESOLUTION_DIRECTIVE, Constants.RESOLUTION_MANDATORY); 232 else 233 result.put(Constants.RESOLUTION_DIRECTIVE, resolution); 234 } 235 result.put(Constants.FILTER_DIRECTIVE, createFilterDirective()); 236 return result; 237 } 238 } 239 createFilterDirective()240 private String createFilterDirective() { 241 StringBuilder filter = new StringBuilder(); 242 filter.append("(&"); //$NON-NLS-1$ 243 synchronized (this.monitor) { 244 addFilterAttribute(filter, BundleRevision.PACKAGE_NAMESPACE, getName(), false); 245 VersionRange range = getVersionRange(); 246 if (range != null && range != VersionRange.emptyRange) 247 addFilterAttribute(filter, Constants.VERSION_ATTRIBUTE, range); 248 if (symbolicName != null) 249 addFilterAttribute(filter, Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, symbolicName); 250 if (bundleVersionRange != null) 251 addFilterAttribute(filter, Constants.BUNDLE_VERSION_ATTRIBUTE, bundleVersionRange); 252 if (attributes != null) 253 addFilterAttributes(filter, attributes); 254 } 255 filter.append(')'); 256 return filter.toString(); 257 } 258 259 @Override getInteralAttributes()260 protected Map<String, Object> getInteralAttributes() { 261 return Collections.<String, Object> emptyMap(); 262 } 263 264 @Override getInternalNameSpace()265 protected String getInternalNameSpace() { 266 return BundleRevision.PACKAGE_NAMESPACE; 267 } 268 } 269