1 /******************************************************************************* 2 * Copyright (c) 2003, 2018 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 *******************************************************************************/ 15 package org.eclipse.osgi.internal.resolver; 16 17 import java.lang.reflect.Constructor; 18 import java.util.ArrayList; 19 import java.util.Collections; 20 import java.util.Dictionary; 21 import java.util.Enumeration; 22 import java.util.HashMap; 23 import java.util.HashSet; 24 import java.util.Hashtable; 25 import java.util.Iterator; 26 import java.util.List; 27 import java.util.Map; 28 import java.util.Set; 29 import org.eclipse.osgi.internal.framework.EquinoxContainer; 30 import org.eclipse.osgi.internal.framework.FilterImpl; 31 import org.eclipse.osgi.internal.messages.Msg; 32 import org.eclipse.osgi.internal.util.Tokenizer; 33 import org.eclipse.osgi.service.resolver.BundleDescription; 34 import org.eclipse.osgi.service.resolver.BundleSpecification; 35 import org.eclipse.osgi.service.resolver.ExportPackageDescription; 36 import org.eclipse.osgi.service.resolver.GenericDescription; 37 import org.eclipse.osgi.service.resolver.GenericSpecification; 38 import org.eclipse.osgi.service.resolver.HostSpecification; 39 import org.eclipse.osgi.service.resolver.ImportPackageSpecification; 40 import org.eclipse.osgi.service.resolver.NativeCodeSpecification; 41 import org.eclipse.osgi.service.resolver.State; 42 import org.eclipse.osgi.service.resolver.VersionRange; 43 import org.eclipse.osgi.util.ManifestElement; 44 import org.eclipse.osgi.util.NLS; 45 import org.osgi.framework.BundleException; 46 import org.osgi.framework.Constants; 47 import org.osgi.framework.InvalidSyntaxException; 48 import org.osgi.framework.Version; 49 import org.osgi.framework.namespace.BundleNamespace; 50 import org.osgi.framework.namespace.IdentityNamespace; 51 import org.osgi.resource.Namespace; 52 53 /** 54 * This class builds bundle description objects from manifests 55 */ 56 public class StateBuilder { 57 private static final String[] DEFINED_EXPORT_PACKAGE_DIRECTIVES = {Constants.USES_DIRECTIVE, Constants.INCLUDE_DIRECTIVE, Constants.EXCLUDE_DIRECTIVE, StateImpl.FRIENDS_DIRECTIVE, StateImpl.INTERNAL_DIRECTIVE, Constants.MANDATORY_DIRECTIVE}; 58 private static final String[] DEFINED_IMPORT_PACKAGE_DIRECTIVES = {Constants.RESOLUTION_DIRECTIVE}; 59 private static final String[] DEFINED_PACKAGE_MATCHING_ATTRS = {Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, Constants.BUNDLE_VERSION_ATTRIBUTE, Constants.PACKAGE_SPECIFICATION_VERSION, Constants.VERSION_ATTRIBUTE}; 60 private static final String[] DEFINED_REQUIRE_BUNDLE_DIRECTIVES = {Constants.RESOLUTION_DIRECTIVE, Constants.VISIBILITY_DIRECTIVE}; 61 private static final String[] DEFINED_FRAGMENT_HOST_DIRECTIVES = {Constants.EXTENSION_DIRECTIVE}; 62 static final String[] DEFINED_BSN_DIRECTIVES = {Constants.SINGLETON_DIRECTIVE, Constants.FRAGMENT_ATTACHMENT_DIRECTIVE, Constants.MANDATORY_DIRECTIVE}; 63 static final String[] DEFINED_BSN_MATCHING_ATTRS = {Constants.BUNDLE_VERSION_ATTRIBUTE, StateImpl.OPTIONAL_ATTRIBUTE, StateImpl.REPROVIDE_ATTRIBUTE}; 64 private static final String[] DEFINED_REQUIRE_CAPABILITY_DIRECTIVES = {Constants.RESOLUTION_DIRECTIVE, Constants.FILTER_DIRECTIVE, Namespace.REQUIREMENT_CARDINALITY_DIRECTIVE}; 65 private static final String[] DEFINED_REQUIRE_CAPABILITY_ATTRS = {}; 66 private static final String[] DEFINED_OSGI_VALIDATE_HEADERS = {Constants.IMPORT_PACKAGE, Constants.DYNAMICIMPORT_PACKAGE, Constants.EXPORT_PACKAGE, Constants.FRAGMENT_HOST, Constants.BUNDLE_SYMBOLICNAME, Constants.REQUIRE_BUNDLE}; 67 static final String GENERIC_REQUIRE = "Eclipse-GenericRequire"; //$NON-NLS-1$ 68 static final String GENERIC_CAPABILITY = "Eclipse-GenericCapability"; //$NON-NLS-1$ 69 70 private static final String ATTR_TYPE_STRING = "string"; //$NON-NLS-1$ 71 private static final String ATTR_TYPE_VERSION = "version"; //$NON-NLS-1$ 72 private static final String ATTR_TYPE_URI = "uri"; //$NON-NLS-1$ 73 private static final String ATTR_TYPE_LONG = "long"; //$NON-NLS-1$ 74 private static final String ATTR_TYPE_DOUBLE = "double"; //$NON-NLS-1$ 75 private static final String ATTR_TYPE_SET = "set"; //$NON-NLS-1$ 76 private static final String ATTR_TYPE_LIST = "List"; //$NON-NLS-1$ 77 private static final String OPTIONAL_ATTR = "optional"; //$NON-NLS-1$ 78 private static final String MULTIPLE_ATTR = "multiple"; //$NON-NLS-1$ 79 private static final String TRUE = "true"; //$NON-NLS-1$ 80 createBundleDescription(StateImpl state, Dictionary<String, String> manifest, String location)81 static BundleDescription createBundleDescription(StateImpl state, Dictionary<String, String> manifest, String location) throws BundleException { 82 BundleDescriptionImpl result = new BundleDescriptionImpl(); 83 String manifestVersionHeader = manifest.get(Constants.BUNDLE_MANIFESTVERSION); 84 boolean jreBundle = "true".equals(manifest.get(StateImpl.Eclipse_JREBUNDLE)); //$NON-NLS-1$ 85 int manifestVersion = 1; 86 if (manifestVersionHeader != null) 87 manifestVersion = Integer.parseInt(manifestVersionHeader); 88 if (manifestVersion >= 2) 89 validateHeaders(manifest, jreBundle); 90 91 // retrieve the symbolic-name and the singleton status 92 String symbolicNameHeader = manifest.get(Constants.BUNDLE_SYMBOLICNAME); 93 if (symbolicNameHeader != null) { 94 ManifestElement[] symbolicNameElements = ManifestElement.parseHeader(Constants.BUNDLE_SYMBOLICNAME, symbolicNameHeader); 95 if (symbolicNameElements.length > 0) { 96 ManifestElement bsnElement = symbolicNameElements[0]; 97 result.setSymbolicName(bsnElement.getValue()); 98 String singleton = bsnElement.getDirective(Constants.SINGLETON_DIRECTIVE); 99 if (singleton == null) // TODO this is for backward compatibility; need to check manifest version < 2 to allow this after everyone has converted to new syntax 100 singleton = bsnElement.getAttribute(Constants.SINGLETON_DIRECTIVE); 101 result.setStateBit(BundleDescriptionImpl.SINGLETON, "true".equals(singleton)); //$NON-NLS-1$ 102 String fragmentAttachment = bsnElement.getDirective(Constants.FRAGMENT_ATTACHMENT_DIRECTIVE); 103 if (fragmentAttachment != null) { 104 if (fragmentAttachment.equals(Constants.FRAGMENT_ATTACHMENT_RESOLVETIME)) { 105 result.setStateBit(BundleDescriptionImpl.ATTACH_FRAGMENTS, true); 106 result.setStateBit(BundleDescriptionImpl.DYNAMIC_FRAGMENTS, false); 107 } else if (fragmentAttachment.equals(Constants.FRAGMENT_ATTACHMENT_NEVER)) { 108 result.setStateBit(BundleDescriptionImpl.ATTACH_FRAGMENTS, false); 109 result.setStateBit(BundleDescriptionImpl.DYNAMIC_FRAGMENTS, false); 110 } 111 } 112 result.setDirective(Constants.MANDATORY_DIRECTIVE, ManifestElement.getArrayFromList(bsnElement.getDirective(Constants.MANDATORY_DIRECTIVE))); 113 result.setAttributes(getAttributes(bsnElement, DEFINED_BSN_MATCHING_ATTRS)); 114 result.setArbitraryDirectives(getDirectives(bsnElement, DEFINED_BSN_DIRECTIVES)); 115 } 116 } 117 // retrieve other headers 118 String version = manifest.get(Constants.BUNDLE_VERSION); 119 try { 120 result.setVersion((version != null) ? Version.parseVersion(version) : Version.emptyVersion); 121 } catch (IllegalArgumentException ex) { 122 if (manifestVersion >= 2) { 123 String message = NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, Constants.BUNDLE_VERSION, version); 124 throw new BundleException(message + " : " + ex.getMessage(), BundleException.MANIFEST_ERROR, ex); //$NON-NLS-1$ 125 } 126 // prior to R4 the Bundle-Version header was not interpreted by the Framework; 127 // must not fail for old R3 style bundles 128 } 129 result.setLocation(location); 130 result.setPlatformFilter(manifest.get(StateImpl.ECLIPSE_PLATFORMFILTER)); 131 String[] brees = ManifestElement.getArrayFromList(manifest.get(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT)); 132 result.setExecutionEnvironments(brees); 133 ManifestElement[] host = ManifestElement.parseHeader(Constants.FRAGMENT_HOST, manifest.get(Constants.FRAGMENT_HOST)); 134 if (host != null) 135 result.setHost(createHostSpecification(host[0], state)); 136 ManifestElement[] exports = ManifestElement.parseHeader(Constants.EXPORT_PACKAGE, manifest.get(Constants.EXPORT_PACKAGE)); 137 ManifestElement[] provides = ManifestElement.parseHeader(StateImpl.PROVIDE_PACKAGE, manifest.get(StateImpl.PROVIDE_PACKAGE)); 138 boolean strict = state != null && state.inStrictMode(); 139 List<String> providedExports = new ArrayList<>(provides == null ? 0 : provides.length); 140 result.setExportPackages(createExportPackages(exports, provides, providedExports, strict)); 141 ManifestElement[] imports = ManifestElement.parseHeader(Constants.IMPORT_PACKAGE, manifest.get(Constants.IMPORT_PACKAGE)); 142 ManifestElement[] dynamicImports = ManifestElement.parseHeader(Constants.DYNAMICIMPORT_PACKAGE, manifest.get(Constants.DYNAMICIMPORT_PACKAGE)); 143 result.setImportPackages(createImportPackages(result.getExportPackages(), providedExports, imports, dynamicImports, manifestVersion)); 144 ManifestElement[] requires = ManifestElement.parseHeader(Constants.REQUIRE_BUNDLE, manifest.get(Constants.REQUIRE_BUNDLE)); 145 result.setRequiredBundles(createRequiredBundles(requires)); 146 String[][] genericAliases = getGenericAliases(state); 147 ManifestElement[] genericRequires = getGenericRequires(manifest, genericAliases); 148 ManifestElement[] osgiRequires = ManifestElement.parseHeader(Constants.REQUIRE_CAPABILITY, manifest.get(Constants.REQUIRE_CAPABILITY)); 149 result.setGenericRequires(createGenericRequires(genericRequires, osgiRequires, brees)); 150 ManifestElement[] genericCapabilities = getGenericCapabilities(manifest, genericAliases); 151 ManifestElement[] osgiCapabilities = ManifestElement.parseHeader(Constants.PROVIDE_CAPABILITY, manifest.get(Constants.PROVIDE_CAPABILITY)); 152 result.setGenericCapabilities(createGenericCapabilities(genericCapabilities, osgiCapabilities, result)); 153 ManifestElement[] nativeCode = ManifestElement.parseHeader(Constants.BUNDLE_NATIVECODE, manifest.get(Constants.BUNDLE_NATIVECODE)); 154 result.setNativeCodeSpecification(createNativeCode(nativeCode)); 155 return result; 156 } 157 getGenericRequires(Dictionary<String, String> manifest, String[][] genericAliases)158 private static ManifestElement[] getGenericRequires(Dictionary<String, String> manifest, String[][] genericAliases) throws BundleException { 159 ManifestElement[] genericRequires = ManifestElement.parseHeader(GENERIC_REQUIRE, manifest.get(GENERIC_REQUIRE)); 160 List<ManifestElement> aliasList = null; 161 if (genericAliases.length > 0) { 162 aliasList = new ArrayList<>(genericRequires == null ? 0 : genericRequires.length); 163 for (String[] genericAlias : genericAliases) { 164 ManifestElement[] aliasReqs = ManifestElement.parseHeader(genericAlias[1], manifest.get(genericAlias[1])); 165 if (aliasReqs == null) 166 continue; 167 for (ManifestElement aliasReq : aliasReqs) { 168 StringBuilder strBuf = new StringBuilder(); 169 strBuf.append(aliasReq.getValue()).append(':').append(genericAlias[2]); 170 String filter = aliasReq.getAttribute(Constants.SELECTION_FILTER_ATTRIBUTE); 171 if (filter != null) 172 strBuf.append("; ").append(Constants.SELECTION_FILTER_ATTRIBUTE).append(filter).append("=\"").append(filter).append("\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 173 ManifestElement[] withType = ManifestElement.parseHeader(genericAlias[1], strBuf.toString()); 174 aliasList.add(withType[0]); 175 } 176 } 177 } 178 if (aliasList == null || aliasList.size() == 0) 179 return genericRequires; 180 if (genericRequires != null) 181 Collections.addAll(aliasList, genericRequires); 182 return aliasList.toArray(new ManifestElement[aliasList.size()]); 183 } 184 getGenericCapabilities(Dictionary<String, String> manifest, String[][] genericAliases)185 private static ManifestElement[] getGenericCapabilities(Dictionary<String, String> manifest, String[][] genericAliases) throws BundleException { 186 ManifestElement[] genericCapabilities = ManifestElement.parseHeader(GENERIC_CAPABILITY, manifest.get(GENERIC_CAPABILITY)); 187 List<ManifestElement> aliasList = null; 188 if (genericAliases.length > 0) { 189 aliasList = new ArrayList<>(genericCapabilities == null ? 0 : genericCapabilities.length); 190 for (String[] genericAlias : genericAliases) { 191 ManifestElement[] aliasCapabilities = ManifestElement.parseHeader(genericAlias[0], manifest.get(genericAlias[0])); 192 if (aliasCapabilities == null) 193 continue; 194 for (ManifestElement aliasCapability : aliasCapabilities) { 195 StringBuilder strBuf = new StringBuilder(); 196 strBuf.append(aliasCapability.getValue()).append(':').append(genericAlias[2]); 197 for (Enumeration<String> keys = aliasCapability.getKeys(); keys != null && keys.hasMoreElements();) { 198 String key = keys.nextElement(); 199 strBuf.append("; ").append(key).append("=\"").append(aliasCapability.getAttribute(key)).append("\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 200 } 201 ManifestElement[] withTypes = ManifestElement.parseHeader(genericAlias[0], strBuf.toString()); 202 aliasList.add(withTypes[0]); 203 } 204 } 205 } 206 if (aliasList == null || aliasList.size() == 0) 207 return genericCapabilities; 208 if (genericCapabilities != null) 209 Collections.addAll(aliasList, genericCapabilities); 210 return aliasList.toArray(new ManifestElement[aliasList.size()]); 211 } 212 getGenericAliases(StateImpl state)213 private static String[][] getGenericAliases(StateImpl state) { 214 String genericAliasesProp = getPlatformProperty(state, "osgi.genericAliases"); //$NON-NLS-1$ 215 if (genericAliasesProp == null) 216 return new String[0][0]; 217 String[] aliases = ManifestElement.getArrayFromList(genericAliasesProp, ","); //$NON-NLS-1$ 218 String[][] result = new String[aliases.length][]; 219 for (int i = 0; i < aliases.length; i++) 220 result[i] = ManifestElement.getArrayFromList(aliases[i], ":"); //$NON-NLS-1$ 221 return result; 222 } 223 getPlatformProperty(State state, String key)224 private static String getPlatformProperty(State state, String key) { 225 Dictionary<Object, Object>[] platformProps = state == null ? null : state.getPlatformProperties(); 226 return platformProps == null || platformProps.length == 0 ? null : (String) platformProps[0].get(key); 227 } 228 validateHeaders(Dictionary<String, String> manifest, boolean jreBundle)229 private static void validateHeaders(Dictionary<String, String> manifest, boolean jreBundle) throws BundleException { 230 for (String definedOSGiValidateHeader : DEFINED_OSGI_VALIDATE_HEADERS) { 231 String header = manifest.get(definedOSGiValidateHeader); 232 if (header != null) { 233 ManifestElement[] elements = ManifestElement.parseHeader(definedOSGiValidateHeader, header); 234 checkForDuplicateDirectivesAttributes(definedOSGiValidateHeader, elements); 235 if (definedOSGiValidateHeader == Constants.IMPORT_PACKAGE) { 236 checkImportExportSyntax(definedOSGiValidateHeader, elements, false, false, jreBundle); 237 } 238 if (definedOSGiValidateHeader == Constants.DYNAMICIMPORT_PACKAGE) { 239 checkImportExportSyntax(definedOSGiValidateHeader, elements, false, true, jreBundle); 240 } 241 if (definedOSGiValidateHeader == Constants.EXPORT_PACKAGE) { 242 checkImportExportSyntax(definedOSGiValidateHeader, elements, true, false, jreBundle); 243 } 244 if (definedOSGiValidateHeader == Constants.FRAGMENT_HOST) { 245 checkExtensionBundle(definedOSGiValidateHeader, elements); 246 } 247 } else if (definedOSGiValidateHeader == Constants.BUNDLE_SYMBOLICNAME) { 248 throw new BundleException(NLS.bind(StateMsg.HEADER_REQUIRED, Constants.BUNDLE_SYMBOLICNAME), BundleException.MANIFEST_ERROR); 249 } 250 } 251 } 252 createRequiredBundles(ManifestElement[] specs)253 private static BundleSpecification[] createRequiredBundles(ManifestElement[] specs) { 254 if (specs == null) 255 return null; 256 BundleSpecification[] result = new BundleSpecification[specs.length]; 257 for (int i = 0; i < specs.length; i++) 258 result[i] = createRequiredBundle(specs[i]); 259 return result; 260 } 261 createRequiredBundle(ManifestElement spec)262 static BundleSpecification createRequiredBundle(ManifestElement spec) { 263 BundleSpecificationImpl result = new BundleSpecificationImpl(); 264 result.setName(spec.getValue()); 265 result.setVersionRange(getVersionRange(spec.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE))); 266 result.setExported(Constants.VISIBILITY_REEXPORT.equals(spec.getDirective(Constants.VISIBILITY_DIRECTIVE)) || "true".equals(spec.getAttribute(StateImpl.REPROVIDE_ATTRIBUTE))); //$NON-NLS-1$ 267 result.setOptional(Constants.RESOLUTION_OPTIONAL.equals(spec.getDirective(Constants.RESOLUTION_DIRECTIVE)) || "true".equals(spec.getAttribute(StateImpl.OPTIONAL_ATTRIBUTE))); //$NON-NLS-1$ 268 result.setAttributes(getAttributes(spec, DEFINED_BSN_MATCHING_ATTRS)); 269 result.setArbitraryDirectives(getDirectives(spec, DEFINED_REQUIRE_BUNDLE_DIRECTIVES)); 270 return result; 271 } 272 createImportPackages(ExportPackageDescription[] exported, List<String> providedExports, ManifestElement[] imported, ManifestElement[] dynamicImported, int manifestVersion)273 private static ImportPackageSpecification[] createImportPackages(ExportPackageDescription[] exported, List<String> providedExports, ManifestElement[] imported, ManifestElement[] dynamicImported, int manifestVersion) { 274 List<ImportPackageSpecification> allImports = null; 275 if (manifestVersion < 2) { 276 // add implicit imports for each exported package if manifest verions is less than 2. 277 if (exported.length == 0 && imported == null && dynamicImported == null) 278 return null; 279 allImports = new ArrayList<>(exported.length + (imported == null ? 0 : imported.length)); 280 for (ExportPackageDescription exportDescription : exported) { 281 if (providedExports.contains(exportDescription.getName())) { 282 continue; 283 } 284 ImportPackageSpecificationImpl result = new ImportPackageSpecificationImpl(); 285 result.setName(exportDescription.getName()); 286 result.setVersionRange(getVersionRange(exportDescription.getVersion().toString())); 287 result.setDirective(Constants.RESOLUTION_DIRECTIVE, ImportPackageSpecification.RESOLUTION_STATIC); 288 allImports.add(result); 289 } 290 } else { 291 allImports = new ArrayList<>(imported == null ? 0 : imported.length); 292 } 293 294 // add dynamics first so they will get overriden by static imports if 295 // the same package is dyanamically imported and statically imported. 296 if (dynamicImported != null) 297 for (ManifestElement dynamicImport : dynamicImported) { 298 addImportPackages(dynamicImport, allImports, manifestVersion, true); 299 } 300 if (imported != null) 301 for (ManifestElement pkgImport : imported) { 302 addImportPackages(pkgImport, allImports, manifestVersion, false); 303 } 304 return allImports.toArray(new ImportPackageSpecification[allImports.size()]); 305 } 306 addImportPackages(ManifestElement importPackage, List<ImportPackageSpecification> allImports, int manifestVersion, boolean dynamic)307 public static void addImportPackages(ManifestElement importPackage, List<ImportPackageSpecification> allImports, int manifestVersion, boolean dynamic) { 308 String[] importNames = importPackage.getValueComponents(); 309 for (String importName : importNames) { 310 // do not allow for multiple imports of same package of manifest version < 2 311 if (manifestVersion < 2) { 312 Iterator<ImportPackageSpecification> iter = allImports.iterator(); 313 while (iter.hasNext()) { 314 if (importName.equals(iter.next().getName())) { 315 iter.remove(); 316 } 317 } 318 } 319 ImportPackageSpecificationImpl result = new ImportPackageSpecificationImpl(); 320 result.setName(importName); 321 // set common attributes for both dynamic and static imports 322 String versionString = importPackage.getAttribute(Constants.VERSION_ATTRIBUTE); 323 if (versionString == null) // specification-version aliases to version 324 versionString = importPackage.getAttribute(Constants.PACKAGE_SPECIFICATION_VERSION); 325 result.setVersionRange(getVersionRange(versionString)); 326 result.setBundleSymbolicName(importPackage.getAttribute(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)); 327 result.setBundleVersionRange(getVersionRange(importPackage.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE))); 328 // only set the matching attributes if manifest version >= 2 329 if (manifestVersion >= 2) 330 result.setAttributes(getAttributes(importPackage, DEFINED_PACKAGE_MATCHING_ATTRS)); 331 if (dynamic) 332 result.setDirective(Constants.RESOLUTION_DIRECTIVE, ImportPackageSpecification.RESOLUTION_DYNAMIC); 333 else 334 result.setDirective(Constants.RESOLUTION_DIRECTIVE, getResolution(importPackage.getDirective(Constants.RESOLUTION_DIRECTIVE))); 335 result.setArbitraryDirectives(getDirectives(importPackage, DEFINED_IMPORT_PACKAGE_DIRECTIVES)); 336 allImports.add(result); 337 } 338 } 339 getResolution(String resolution)340 private static String getResolution(String resolution) { 341 String result = ImportPackageSpecification.RESOLUTION_STATIC; 342 if (Constants.RESOLUTION_OPTIONAL.equals(resolution) || ImportPackageSpecification.RESOLUTION_DYNAMIC.equals(resolution)) 343 result = resolution; 344 return result; 345 } 346 createExportPackages(ManifestElement[] exported, ManifestElement[] provides, List<String> providedExports, boolean strict)347 static ExportPackageDescription[] createExportPackages(ManifestElement[] exported, ManifestElement[] provides, List<String> providedExports, boolean strict) { 348 int numExports = (exported == null ? 0 : exported.length) + (provides == null ? 0 : provides.length); 349 if (numExports == 0) 350 return null; 351 List<ExportPackageDescription> allExports = new ArrayList<>(numExports); 352 if (exported != null) 353 for (ManifestElement packageExport : exported) { 354 addExportPackages(packageExport, allExports, strict); 355 } 356 if (provides != null) 357 addProvidePackages(provides, allExports, providedExports); 358 return allExports.toArray(new ExportPackageDescription[allExports.size()]); 359 } 360 addExportPackages(ManifestElement exportPackage, List<ExportPackageDescription> allExports, boolean strict)361 static void addExportPackages(ManifestElement exportPackage, List<ExportPackageDescription> allExports, boolean strict) { 362 String[] exportNames = exportPackage.getValueComponents(); 363 for (String exportName : exportNames) { 364 // if we are in strict mode and the package is marked as internal, skip it. 365 if (strict && "true".equals(exportPackage.getDirective(StateImpl.INTERNAL_DIRECTIVE))) //$NON-NLS-1$ 366 continue; 367 ExportPackageDescriptionImpl result = new ExportPackageDescriptionImpl(); 368 result.setName(exportName); 369 String versionString = exportPackage.getAttribute(Constants.VERSION_ATTRIBUTE); 370 if (versionString == null) // specification-version aliases to version 371 versionString = exportPackage.getAttribute(Constants.PACKAGE_SPECIFICATION_VERSION); 372 if (versionString != null) 373 result.setVersion(Version.parseVersion(versionString)); 374 result.setDirective(Constants.USES_DIRECTIVE, ManifestElement.getArrayFromList(exportPackage.getDirective(Constants.USES_DIRECTIVE))); 375 result.setDirective(Constants.INCLUDE_DIRECTIVE, exportPackage.getDirective(Constants.INCLUDE_DIRECTIVE)); 376 result.setDirective(Constants.EXCLUDE_DIRECTIVE, exportPackage.getDirective(Constants.EXCLUDE_DIRECTIVE)); 377 result.setDirective(StateImpl.FRIENDS_DIRECTIVE, ManifestElement.getArrayFromList(exportPackage.getDirective(StateImpl.FRIENDS_DIRECTIVE))); 378 result.setDirective(StateImpl.INTERNAL_DIRECTIVE, Boolean.valueOf(exportPackage.getDirective(StateImpl.INTERNAL_DIRECTIVE))); 379 result.setDirective(Constants.MANDATORY_DIRECTIVE, ManifestElement.getArrayFromList(exportPackage.getDirective(Constants.MANDATORY_DIRECTIVE))); 380 result.setAttributes(getAttributes(exportPackage, DEFINED_PACKAGE_MATCHING_ATTRS)); 381 result.setArbitraryDirectives(getDirectives(exportPackage, DEFINED_EXPORT_PACKAGE_DIRECTIVES)); 382 allExports.add(result); 383 } 384 } 385 addProvidePackages(ManifestElement[] provides, List<ExportPackageDescription> allExports, List<String> providedExports)386 private static void addProvidePackages(ManifestElement[] provides, List<ExportPackageDescription> allExports, List<String> providedExports) { 387 ExportPackageDescription[] currentExports = allExports.toArray(new ExportPackageDescription[allExports.size()]); 388 for (ManifestElement provide : provides) { 389 boolean duplicate = false; 390 for (ExportPackageDescription currentExport : currentExports) { 391 if (provide.getValue().equals(currentExport.getName())) { 392 duplicate = true; 393 break; 394 } 395 } 396 if (!duplicate) { 397 ExportPackageDescriptionImpl result = new ExportPackageDescriptionImpl(); 398 result.setName(provide.getValue()); 399 allExports.add(result); 400 } 401 providedExports.add(provide.getValue()); 402 } 403 } 404 getDirectives(ManifestElement element, String[] definedDirectives)405 static Map<String, String> getDirectives(ManifestElement element, String[] definedDirectives) { 406 Enumeration<String> keys = element.getDirectiveKeys(); 407 if (keys == null) 408 return null; 409 Map<String, String> arbitraryDirectives = null; 410 keyloop: while (keys.hasMoreElements()) { 411 String key = keys.nextElement(); 412 for (String definedDirective : definedDirectives) { 413 if (definedDirective.equals(key)) 414 continue keyloop; 415 } 416 if (arbitraryDirectives == null) 417 arbitraryDirectives = new HashMap<>(); 418 arbitraryDirectives.put(key, element.getDirective(key)); 419 } 420 return arbitraryDirectives; 421 } 422 getAttributes(ManifestElement element, String[] definedAttrs)423 static Map<String, Object> getAttributes(ManifestElement element, String[] definedAttrs) { 424 Enumeration<String> keys = element.getKeys(); 425 Map<String, Object> arbitraryAttrs = null; 426 if (keys == null) 427 return null; 428 while (keys.hasMoreElements()) { 429 boolean definedAttr = false; 430 String key = keys.nextElement(); 431 for (String attr : definedAttrs) { 432 if (attr.equals(key)) { 433 definedAttr = true; 434 break; 435 } 436 } 437 String value = element.getAttribute(key); 438 int colonIndex = key.indexOf(':'); 439 String type = ATTR_TYPE_STRING; 440 if (colonIndex > 0) { 441 type = key.substring(colonIndex + 1).trim(); 442 key = key.substring(0, colonIndex).trim(); 443 } 444 if (!definedAttr) { 445 if (arbitraryAttrs == null) 446 arbitraryAttrs = new HashMap<>(); 447 arbitraryAttrs.put(key, convertValue(type, value)); 448 } 449 } 450 return arbitraryAttrs; 451 } 452 convertValue(String type, String value)453 private static Object convertValue(String type, String value) { 454 455 if (ATTR_TYPE_STRING.equalsIgnoreCase(type)) 456 return value; 457 458 String trimmed = value.trim(); 459 if (ATTR_TYPE_DOUBLE.equalsIgnoreCase(type)) 460 return new Double(trimmed); 461 else if (ATTR_TYPE_LONG.equalsIgnoreCase(type)) 462 return new Long(trimmed); 463 else if (ATTR_TYPE_URI.equalsIgnoreCase(type)) 464 try { 465 Class<?> uriClazz = Class.forName("java.net.URI"); //$NON-NLS-1$ 466 Constructor<?> constructor = uriClazz.getConstructor(new Class[] {String.class}); 467 return constructor.newInstance(new Object[] {trimmed}); 468 } catch (ClassNotFoundException e) { 469 // oh well cannot support; just use string 470 return value; 471 } catch (RuntimeException e) { // got some reflection exception 472 throw e; 473 } catch (Exception e) { 474 throw new RuntimeException(e.getMessage(), e); 475 } 476 else if (ATTR_TYPE_VERSION.equalsIgnoreCase(type)) 477 return new Version(trimmed); 478 else if (ATTR_TYPE_SET.equalsIgnoreCase(type)) 479 return ManifestElement.getArrayFromList(trimmed, ","); //$NON-NLS-1$ 480 481 // assume list type, anything else will throw an exception 482 Tokenizer listTokenizer = new Tokenizer(type); 483 String listType = listTokenizer.getToken("<"); //$NON-NLS-1$ 484 if (!ATTR_TYPE_LIST.equalsIgnoreCase(listType)) 485 throw new RuntimeException("Unsupported type: " + type); //$NON-NLS-1$ 486 char c = listTokenizer.getChar(); 487 String componentType = ATTR_TYPE_STRING; 488 if (c == '<') { 489 componentType = listTokenizer.getToken(">"); //$NON-NLS-1$ 490 if (listTokenizer.getChar() != '>') 491 throw new RuntimeException("Invalid type, missing ending '>' : " + type); //$NON-NLS-1$ 492 } 493 List<String> tokens = new Tokenizer(value).getEscapedTokens(","); //$NON-NLS-1$ 494 List<Object> components = new ArrayList<>(); 495 for (String component : tokens) { 496 components.add(convertValue(componentType, component)); 497 } 498 return components; 499 } 500 createHostSpecification(ManifestElement spec, State state)501 static HostSpecification createHostSpecification(ManifestElement spec, State state) { 502 if (spec == null) 503 return null; 504 HostSpecificationImpl result = new HostSpecificationImpl(); 505 result.setName(spec.getValue()); 506 result.setVersionRange(getVersionRange(spec.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE))); 507 String multiple = spec.getDirective("multiple-hosts"); //$NON-NLS-1$ 508 if (multiple == null) 509 multiple = getPlatformProperty(state, "osgi.support.multipleHosts"); //$NON-NLS-1$ 510 result.setIsMultiHost("true".equals(multiple)); //$NON-NLS-1$ 511 result.setAttributes(getAttributes(spec, DEFINED_BSN_MATCHING_ATTRS)); 512 result.setArbitraryDirectives(getDirectives(spec, DEFINED_FRAGMENT_HOST_DIRECTIVES)); 513 return result; 514 } 515 createGenericRequires(ManifestElement[] equinoxRequires, ManifestElement[] osgiRequires, String[] brees)516 private static GenericSpecification[] createGenericRequires(ManifestElement[] equinoxRequires, ManifestElement[] osgiRequires, String[] brees) throws BundleException { 517 List<GenericSpecification> result = createEquinoxRequires(equinoxRequires); 518 result = createOSGiRequires(osgiRequires, result); 519 result = convertBREEs(brees, result); 520 return result == null ? null : result.toArray(new GenericSpecification[result.size()]); 521 } 522 convertBREEs(String[] brees, List<GenericSpecification> result)523 static List<GenericSpecification> convertBREEs(String[] brees, List<GenericSpecification> result) throws BundleException { 524 if (brees == null || brees.length == 0) 525 return result; 526 if (result == null) 527 result = new ArrayList<>(brees.length); 528 List<String> breeFilters = new ArrayList<>(); 529 for (String bree : brees) 530 breeFilters.add(createOSGiEERequirementFilter(bree)); 531 String filterSpec; 532 if (breeFilters.size() == 1) { 533 filterSpec = breeFilters.get(0); 534 } else { 535 StringBuilder filterBuf = new StringBuilder("(|"); //$NON-NLS-1$ 536 for (String breeFilter : breeFilters) { 537 filterBuf.append(breeFilter); 538 } 539 filterSpec = filterBuf.append(")").toString(); //$NON-NLS-1$ 540 } 541 GenericSpecificationImpl spec = new GenericSpecificationImpl(); 542 spec.setResolution(GenericSpecificationImpl.RESOLUTION_FROM_BREE); 543 spec.setType(StateImpl.OSGI_EE_NAMESPACE); 544 try { 545 FilterImpl filter = FilterImpl.newInstance(filterSpec); 546 spec.setMatchingFilter(filter); 547 String name = filter.getPrimaryKeyValue(spec.getType()); 548 if (name != null) 549 spec.setName(name); 550 } catch (InvalidSyntaxException e) { 551 throw new BundleException("Error converting required execution environment.", e); //$NON-NLS-1$ 552 } 553 result.add(spec); 554 return result; 555 } 556 createOSGiEERequirementFilter(String bree)557 private static String createOSGiEERequirementFilter(String bree) throws BundleException { 558 String[] nameVersion = getOSGiEENameVersion(bree); 559 String eeName = nameVersion[0]; 560 String v = nameVersion[1]; 561 String filterSpec; 562 if (v == null) 563 filterSpec = "(osgi.ee=" + eeName + ")"; //$NON-NLS-1$ //$NON-NLS-2$ 564 else 565 filterSpec = "(&(osgi.ee=" + eeName + ")(version=" + v + "))"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 566 try { 567 // do a sanity check 568 FilterImpl.newInstance(filterSpec); 569 } catch (InvalidSyntaxException e) { 570 filterSpec = "(osgi.ee=" + bree + ")"; //$NON-NLS-1$ //$NON-NLS-2$ 571 try { 572 // do another sanity check 573 FilterImpl.newInstance(filterSpec); 574 } catch (InvalidSyntaxException e1) { 575 throw new BundleException("Error converting required execution environment.", e1); //$NON-NLS-1$ 576 } 577 } 578 return filterSpec; 579 } 580 getOSGiEENameVersion(String bree)581 static String[] getOSGiEENameVersion(String bree) { 582 String ee1 = null; 583 String ee2 = null; 584 String v1 = null; 585 String v2 = null; 586 int separator = bree.indexOf('/'); 587 if (separator <= 0 || separator == bree.length() - 1) { 588 ee1 = bree; 589 } else { 590 ee1 = bree.substring(0, separator); 591 ee2 = bree.substring(separator + 1); 592 } 593 int v1idx = ee1.indexOf('-'); 594 if (v1idx > 0 && v1idx < ee1.length() - 1) { 595 // check for > 0 to avoid EEs starting with - 596 // check for < len - 1 to avoid ending with - 597 try { 598 v1 = ee1.substring(v1idx + 1); 599 // sanity check version format 600 Version.parseVersion(v1); 601 ee1 = ee1.substring(0, v1idx); 602 } catch (IllegalArgumentException e) { 603 v1 = null; 604 } 605 } 606 607 int v2idx = ee2 == null ? -1 : ee2.indexOf('-'); 608 if (v2idx > 0 && v2idx < ee2.length() - 1) { 609 // check for > 0 to avoid EEs starting with - 610 // check for < len - 1 to avoid ending with - 611 try { 612 v2 = ee2.substring(v2idx + 1); 613 Version.parseVersion(v2); 614 ee2 = ee2.substring(0, v2idx); 615 } catch (IllegalArgumentException e) { 616 v2 = null; 617 } 618 } 619 620 if (v1 == null) 621 v1 = v2; 622 if (v1 != null && v2 != null && !v1.equals(v2)) { 623 ee1 = bree; 624 ee2 = null; 625 v1 = null; 626 v2 = null; 627 } 628 if ("J2SE".equals(ee1)) //$NON-NLS-1$ 629 ee1 = "JavaSE"; //$NON-NLS-1$ 630 if ("J2SE".equals(ee2)) //$NON-NLS-1$ 631 ee2 = "JavaSE"; //$NON-NLS-1$ 632 633 String eeName = ee1 + (ee2 == null ? "" : '/' + ee2); //$NON-NLS-1$ 634 635 return new String[] {eeName, v1}; 636 } 637 createOSGiRequires(ManifestElement[] osgiRequires, List<GenericSpecification> result)638 static List<GenericSpecification> createOSGiRequires(ManifestElement[] osgiRequires, List<GenericSpecification> result) throws BundleException { 639 if (osgiRequires == null) 640 return result; 641 if (result == null) 642 result = new ArrayList<>(); 643 for (ManifestElement element : osgiRequires) { 644 String[] namespaces = element.getValueComponents(); 645 for (String namespace : namespaces) { 646 GenericSpecificationImpl spec = new GenericSpecificationImpl(); 647 spec.setType(namespace); 648 String filterSpec = element.getDirective(Constants.FILTER_DIRECTIVE); 649 if (filterSpec != null) { 650 try { 651 FilterImpl filter = FilterImpl.newInstance(filterSpec); 652 spec.setMatchingFilter(filter); 653 String name = filter.getPrimaryKeyValue(namespace); 654 if (name != null) 655 spec.setName(name); 656 } catch (InvalidSyntaxException e) { 657 String message = NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, Constants.REQUIRE_CAPABILITY, element.toString()); 658 throw new BundleException(message + " : filter", BundleException.MANIFEST_ERROR, e); //$NON-NLS-1$ 659 } 660 } 661 String resolutionDirective = element.getDirective(Constants.RESOLUTION_DIRECTIVE); 662 int resolution = 0; 663 if (Constants.RESOLUTION_OPTIONAL.equals(resolutionDirective)) 664 resolution |= GenericSpecification.RESOLUTION_OPTIONAL; 665 String cardinality = element.getDirective(Namespace.REQUIREMENT_CARDINALITY_DIRECTIVE); 666 if (Namespace.CARDINALITY_MULTIPLE.equals(cardinality)) 667 resolution |= GenericSpecification.RESOLUTION_MULTIPLE; 668 spec.setResolution(resolution); 669 spec.setAttributes(getAttributes(element, DEFINED_REQUIRE_CAPABILITY_ATTRS)); 670 spec.setArbitraryDirectives(getDirectives(element, DEFINED_REQUIRE_CAPABILITY_DIRECTIVES)); 671 result.add(spec); 672 } 673 } 674 return result; 675 } 676 createEquinoxRequires(ManifestElement[] equinoxRequires)677 private static List<GenericSpecification> createEquinoxRequires(ManifestElement[] equinoxRequires) throws BundleException { 678 if (equinoxRequires == null) 679 return null; 680 ArrayList<GenericSpecification> results = new ArrayList<>(equinoxRequires.length); 681 for (ManifestElement equinoxRequire : equinoxRequires) { 682 String[] genericNames = equinoxRequire.getValueComponents(); 683 for (String genericName : genericNames) { 684 GenericSpecificationImpl spec = new GenericSpecificationImpl(); 685 int colonIdx = genericName.indexOf(':'); 686 if (colonIdx > 0) { 687 spec.setName(genericName.substring(0, colonIdx)); 688 spec.setType(genericName.substring(colonIdx + 1)); 689 } else { 690 spec.setName(genericName); 691 } 692 try { 693 spec.setMatchingFilter(equinoxRequire.getAttribute(Constants.SELECTION_FILTER_ATTRIBUTE), true); 694 } catch (InvalidSyntaxException e) { 695 String message = NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, GENERIC_REQUIRE, equinoxRequire.toString()); 696 throw new BundleException(message + " : " + Constants.SELECTION_FILTER_ATTRIBUTE, BundleException.MANIFEST_ERROR, e); //$NON-NLS-1$ 697 } 698 String optional = equinoxRequire.getAttribute(OPTIONAL_ATTR); 699 String multiple = equinoxRequire.getAttribute(MULTIPLE_ATTR); 700 int resolution = 0; 701 if (TRUE.equals(optional)) 702 resolution |= GenericSpecification.RESOLUTION_OPTIONAL; 703 if (TRUE.equals(multiple)) 704 resolution |= GenericSpecification.RESOLUTION_MULTIPLE; 705 spec.setResolution(resolution); 706 results.add(spec); 707 } 708 } 709 return results; 710 } 711 createGenericCapabilities(ManifestElement[] equinoxCapabilities, ManifestElement[] osgiCapabilities, BundleDescription description)712 private static GenericDescription[] createGenericCapabilities(ManifestElement[] equinoxCapabilities, ManifestElement[] osgiCapabilities, BundleDescription description) throws BundleException { 713 List<GenericDescription> result = createEquinoxCapabilities(equinoxCapabilities); 714 result = createOSGiCapabilities(osgiCapabilities, result, description); 715 return result == null ? null : result.toArray(new GenericDescription[result.size()]); 716 } 717 createOSGiCapabilities(ManifestElement[] osgiCapabilities, List<GenericDescription> result, BundleDescription description)718 static List<GenericDescription> createOSGiCapabilities(ManifestElement[] osgiCapabilities, List<GenericDescription> result, BundleDescription description) throws BundleException { 719 if (result == null) 720 result = new ArrayList<>(osgiCapabilities == null ? 1 : osgiCapabilities.length + 1); 721 // Always have an osgi.identity capability if there is a symbolic name. 722 GenericDescription osgiIdentity = createOsgiIdentityCapability(description); 723 if (osgiIdentity != null) 724 // always add the capability to the front 725 result.add(0, osgiIdentity); 726 return createOSGiCapabilities(osgiCapabilities, result, (Integer) null); 727 } 728 createOSGiCapabilities(ManifestElement[] osgiCapabilities, List<GenericDescription> result, Integer profileIndex)729 static List<GenericDescription> createOSGiCapabilities(ManifestElement[] osgiCapabilities, List<GenericDescription> result, Integer profileIndex) throws BundleException { 730 if (osgiCapabilities == null) 731 return result; 732 if (result == null) 733 result = new ArrayList<>(osgiCapabilities.length); 734 735 for (ManifestElement element : osgiCapabilities) { 736 String[] namespaces = element.getValueComponents(); 737 for (String namespace : namespaces) { 738 if (IdentityNamespace.IDENTITY_NAMESPACE.equals(namespace)) 739 throw new BundleException("A bundle is not allowed to define a capability in the " + IdentityNamespace.IDENTITY_NAMESPACE + " name space."); //$NON-NLS-1$ //$NON-NLS-2$ 740 741 GenericDescriptionImpl desc = new GenericDescriptionImpl(); 742 desc.setType(namespace); 743 Map<String, Object> mapAttrs = getAttributes(element, new String[0]); 744 if (profileIndex != null) 745 mapAttrs.put(ExportPackageDescriptionImpl.EQUINOX_EE, profileIndex); 746 Dictionary<String, Object> attrs = mapAttrs == null ? new Hashtable<String, Object>() : new Hashtable<>(mapAttrs); 747 desc.setAttributes(attrs); 748 Map<String, String> directives = new HashMap<>(); 749 Enumeration<String> keys = element.getDirectiveKeys(); 750 if (keys != null) 751 for (keys = element.getDirectiveKeys(); keys.hasMoreElements();) { 752 String key = keys.nextElement(); 753 directives.put(key, element.getDirective(key)); 754 } 755 desc.setDirectives(directives); 756 result.add(desc); 757 } 758 } 759 return result; 760 } 761 createEquinoxCapabilities(ManifestElement[] equinoxCapabilities)762 private static List<GenericDescription> createEquinoxCapabilities(ManifestElement[] equinoxCapabilities) throws BundleException { 763 if (equinoxCapabilities == null) 764 return null; 765 ArrayList<GenericDescription> results = new ArrayList<>(equinoxCapabilities.length); 766 for (ManifestElement equinoxCapability : equinoxCapabilities) { 767 String[] genericNames = equinoxCapability.getValueComponents(); 768 for (String genericName : genericNames) { 769 GenericDescriptionImpl desc = new GenericDescriptionImpl(); 770 String name = genericName; 771 int colonIdx = genericName.indexOf(':'); 772 if (colonIdx > 0) { 773 name = genericName.substring(0, colonIdx); 774 desc.setType(genericName.substring(colonIdx + 1)); 775 if (IdentityNamespace.IDENTITY_NAMESPACE.equals(desc.getType())) 776 throw new BundleException("A bundle is not allowed to define a capability in the " + IdentityNamespace.IDENTITY_NAMESPACE + " name space."); //$NON-NLS-1$ //$NON-NLS-2$ 777 } 778 Map<String, Object> mapAttrs = getAttributes(equinoxCapability, new String[] {Constants.VERSION_ATTRIBUTE}); 779 Dictionary<String, Object> attrs = mapAttrs == null ? new Hashtable<String, Object>() : new Hashtable<>(mapAttrs); 780 attrs.put(desc.getType(), name); 781 String versionString = equinoxCapability.getAttribute(Constants.VERSION_ATTRIBUTE); 782 if (versionString != null) 783 attrs.put(Constants.VERSION_ATTRIBUTE, Version.parseVersion(versionString)); 784 desc.setAttributes(attrs); 785 results.add(desc); 786 } 787 } 788 return results; 789 } 790 createNativeCode(ManifestElement[] nativeCode)791 private static NativeCodeSpecification createNativeCode(ManifestElement[] nativeCode) throws BundleException { 792 if (nativeCode == null) 793 return null; 794 NativeCodeSpecificationImpl result = new NativeCodeSpecificationImpl(); 795 result.setName(Constants.BUNDLE_NATIVECODE); 796 int length = nativeCode.length; 797 if (length > 0 && nativeCode[length - 1].getValue().equals("*")) { //$NON-NLS-1$ 798 result.setOptional(true); 799 length--; 800 } 801 NativeCodeDescriptionImpl[] suppliers = new NativeCodeDescriptionImpl[length]; 802 for (int i = 0; i < length; i++) { 803 suppliers[i] = createNativeCodeDescription(nativeCode[i]); 804 } 805 result.setPossibleSuppliers(suppliers); 806 return result; 807 } 808 createNativeCodeDescription(ManifestElement manifestElement)809 private static NativeCodeDescriptionImpl createNativeCodeDescription(ManifestElement manifestElement) throws BundleException { 810 NativeCodeDescriptionImpl result = new NativeCodeDescriptionImpl(); 811 result.setName(Constants.BUNDLE_NATIVECODE); 812 result.setNativePaths(manifestElement.getValueComponents()); 813 result.setOSNames(manifestElement.getAttributes(Constants.BUNDLE_NATIVECODE_OSNAME)); 814 result.setProcessors(manifestElement.getAttributes(Constants.BUNDLE_NATIVECODE_PROCESSOR)); 815 result.setOSVersions(createVersionRanges(manifestElement.getAttributes(Constants.BUNDLE_NATIVECODE_OSVERSION))); 816 result.setLanguages(manifestElement.getAttributes(Constants.BUNDLE_NATIVECODE_LANGUAGE)); 817 try { 818 result.setFilter(manifestElement.getAttribute(Constants.SELECTION_FILTER_ATTRIBUTE)); 819 } catch (InvalidSyntaxException e) { 820 String message = NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, Constants.BUNDLE_NATIVECODE, manifestElement.toString()); 821 throw new BundleException(message + " : " + Constants.SELECTION_FILTER_ATTRIBUTE, BundleException.MANIFEST_ERROR, e); //$NON-NLS-1$ 822 } 823 return result; 824 } 825 createVersionRanges(String[] ranges)826 private static VersionRange[] createVersionRanges(String[] ranges) { 827 if (ranges == null) 828 return null; 829 VersionRange[] result = new VersionRange[ranges.length]; 830 for (int i = 0; i < result.length; i++) 831 result[i] = new VersionRange(ranges[i]); 832 return result; 833 } 834 getVersionRange(String versionRange)835 private static VersionRange getVersionRange(String versionRange) { 836 if (versionRange == null) 837 return null; 838 return new VersionRange(versionRange); 839 } 840 checkImportExportSyntax(String headerKey, ManifestElement[] elements, boolean export, boolean dynamic, boolean jreBundle)841 public static void checkImportExportSyntax(String headerKey, ManifestElement[] elements, boolean export, boolean dynamic, boolean jreBundle) throws BundleException { 842 if (elements == null) 843 return; 844 int length = elements.length; 845 Set<String> packages = new HashSet<>(length); 846 for (int i = 0; i < length; i++) { 847 // check for duplicate imports 848 String[] packageNames = elements[i].getValueComponents(); 849 for (String packageName : packageNames) { 850 if (!export && !dynamic && packages.contains(packageName)) { 851 String message = NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, headerKey, elements[i].toString()); 852 throw new BundleException(message + " : " + NLS.bind(StateMsg.HEADER_PACKAGE_DUPLICATES, packageName), BundleException.MANIFEST_ERROR); //$NON-NLS-1$ 853 } 854 // check for java.* 855 if (export && !jreBundle && packageName.startsWith("java.")) { //$NON-NLS-1$ 856 String message = NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, headerKey, elements[i].toString()); 857 throw new BundleException(message + " : " + NLS.bind(StateMsg.HEADER_PACKAGE_JAVA, packageName), BundleException.MANIFEST_ERROR); //$NON-NLS-1$ 858 } 859 packages.add(packageName); 860 } 861 // check for version/specification version mismatch 862 String version = elements[i].getAttribute(Constants.VERSION_ATTRIBUTE); 863 if (version != null) { 864 String specVersion = elements[i].getAttribute(Constants.PACKAGE_SPECIFICATION_VERSION); 865 if (specVersion != null && !specVersion.equals(version)) 866 throw new BundleException(NLS.bind(StateMsg.HEADER_VERSION_ERROR, Constants.VERSION_ATTRIBUTE, Constants.PACKAGE_SPECIFICATION_VERSION), BundleException.MANIFEST_ERROR); 867 } 868 // check for bundle-symbolic-name and bundle-verion attibures 869 // (failure) 870 if (export) { 871 if (elements[i].getAttribute(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE) != null) { 872 String message = NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, headerKey, elements[i].toString()); 873 throw new BundleException(message + " : " + NLS.bind(StateMsg.HEADER_EXPORT_ATTR_ERROR, Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, Constants.EXPORT_PACKAGE), BundleException.MANIFEST_ERROR); //$NON-NLS-1$ 874 } 875 if (elements[i].getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE) != null) { 876 String message = NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, headerKey, elements[i].toString()); 877 throw new BundleException(NLS.bind(message + " : " + StateMsg.HEADER_EXPORT_ATTR_ERROR, Constants.BUNDLE_VERSION_ATTRIBUTE, Constants.EXPORT_PACKAGE), BundleException.MANIFEST_ERROR); //$NON-NLS-1$ 878 } 879 } 880 } 881 } 882 checkForDuplicateDirectivesAttributes(String headerKey, ManifestElement[] elements)883 private static void checkForDuplicateDirectivesAttributes(String headerKey, ManifestElement[] elements) throws BundleException { 884 // check for duplicate directives 885 for (ManifestElement element : elements) { 886 Enumeration<String> directiveKeys = element.getDirectiveKeys(); 887 if (directiveKeys != null) { 888 while (directiveKeys.hasMoreElements()) { 889 String key = directiveKeys.nextElement(); 890 String[] directives = element.getDirectives(key); 891 if (directives.length > 1) { 892 String message = NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, headerKey, element.toString()); 893 throw new BundleException(NLS.bind(message + " : " + StateMsg.HEADER_DIRECTIVE_DUPLICATES, key), BundleException.MANIFEST_ERROR); //$NON-NLS-1$ 894 } 895 } 896 } 897 Enumeration<String> attrKeys = element.getKeys(); 898 if (attrKeys != null) { 899 while (attrKeys.hasMoreElements()) { 900 String key = attrKeys.nextElement(); 901 String[] attrs = element.getAttributes(key); 902 if (attrs.length > 1) { 903 String message = NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, headerKey, element.toString()); 904 throw new BundleException(message + " : " + NLS.bind(StateMsg.HEADER_ATTRIBUTE_DUPLICATES, key), BundleException.MANIFEST_ERROR); //$NON-NLS-1$ 905 } 906 } 907 } 908 } 909 } 910 checkExtensionBundle(String headerKey, ManifestElement[] elements)911 private static void checkExtensionBundle(String headerKey, ManifestElement[] elements) throws BundleException { 912 if (elements.length == 0 || elements[0].getDirective(Constants.EXTENSION_DIRECTIVE) == null) 913 return; 914 String hostName = elements[0].getValue(); 915 // XXX: The extension bundle check is done against system.bundle and org.eclipse.osgi 916 if (!hostName.equals(Constants.SYSTEM_BUNDLE_SYMBOLICNAME) && !hostName.equals(EquinoxContainer.NAME)) { 917 String message = NLS.bind(Msg.MANIFEST_INVALID_HEADER_EXCEPTION, headerKey, elements[0].toString()); 918 throw new BundleException(message + " : " + NLS.bind(StateMsg.HEADER_EXTENSION_ERROR, hostName), BundleException.MANIFEST_ERROR); //$NON-NLS-1$ 919 } 920 } 921 createOsgiIdentityCapability(BundleDescription description)922 static GenericDescription createOsgiIdentityCapability(BundleDescription description) { 923 if (description.getSymbolicName() == null) 924 return null; 925 GenericDescriptionImpl result = new GenericDescriptionImpl(); 926 result.setType(IdentityNamespace.IDENTITY_NAMESPACE); 927 Dictionary<String, Object> attributes = new Hashtable<>(description.getDeclaredAttributes()); 928 // remove osgi.wiring.bundle and bundle-version attributes 929 attributes.remove(BundleNamespace.BUNDLE_NAMESPACE); 930 attributes.remove(Constants.BUNDLE_VERSION_ATTRIBUTE); 931 attributes.put(IdentityNamespace.IDENTITY_NAMESPACE, description.getSymbolicName()); 932 attributes.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE, description.getHost() == null ? IdentityNamespace.TYPE_BUNDLE : IdentityNamespace.TYPE_FRAGMENT); 933 attributes.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE, description.getVersion()); 934 result.setAttributes(attributes); 935 Map<String, String> directives = new HashMap<>(description.getDeclaredDirectives()); 936 // remove defaults directive values 937 if (!description.isSingleton()) 938 directives.remove(Constants.SINGLETON_DIRECTIVE); 939 if (description.attachFragments() && description.dynamicFragments()) 940 directives.remove(Constants.FRAGMENT_ATTACHMENT_DIRECTIVE); 941 result.setDirectives(directives); 942 return result; 943 } 944 } 945