1 /******************************************************************************* 2 * Copyright (c) 2003, 2017 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 *******************************************************************************/ 14 15 package org.eclipse.osgi.internal.framework.legacy; 16 17 import java.security.AccessController; 18 import java.security.PrivilegedAction; 19 import java.util.ArrayList; 20 import java.util.Arrays; 21 import java.util.Collection; 22 import java.util.Collections; 23 import java.util.Comparator; 24 import java.util.HashSet; 25 import java.util.List; 26 import java.util.Map; 27 import java.util.Set; 28 import org.eclipse.osgi.container.Module; 29 import org.eclipse.osgi.container.ModuleCapability; 30 import org.eclipse.osgi.container.ModuleContainer; 31 import org.eclipse.osgi.container.ModuleRevision; 32 import org.eclipse.osgi.container.ModuleWire; 33 import org.eclipse.osgi.container.ModuleWiring; 34 import org.eclipse.osgi.internal.container.Capabilities; 35 import org.eclipse.osgi.internal.container.InternalUtils; 36 import org.eclipse.osgi.internal.framework.EquinoxContainer; 37 import org.osgi.framework.Bundle; 38 import org.osgi.framework.Constants; 39 import org.osgi.framework.FrameworkUtil; 40 import org.osgi.framework.Version; 41 import org.osgi.framework.VersionRange; 42 import org.osgi.framework.namespace.BundleNamespace; 43 import org.osgi.framework.namespace.HostNamespace; 44 import org.osgi.framework.namespace.IdentityNamespace; 45 import org.osgi.framework.namespace.PackageNamespace; 46 import org.osgi.framework.wiring.BundleCapability; 47 import org.osgi.framework.wiring.BundleRevision; 48 import org.osgi.framework.wiring.BundleWire; 49 import org.osgi.framework.wiring.BundleWiring; 50 import org.osgi.resource.Namespace; 51 import org.osgi.resource.Requirement; 52 import org.osgi.service.packageadmin.ExportedPackage; 53 import org.osgi.service.packageadmin.PackageAdmin; 54 import org.osgi.service.packageadmin.RequiredBundle; 55 56 @Deprecated 57 public class PackageAdminImpl implements PackageAdmin { 58 private final ModuleContainer container; 59 60 /* 61 * We need to make sure that the GetBundleAction class loads early to prevent a ClassCircularityError when checking permissions. 62 * See bug 161561 63 */ 64 static { 65 Class<?> c; 66 c = GetBundleAction.class; c.getName()67 c.getName(); // to prevent compiler warnings 68 } 69 70 static class GetBundleAction implements PrivilegedAction<Bundle> { 71 private Class<?> clazz; 72 private PackageAdminImpl impl; 73 GetBundleAction(PackageAdminImpl impl, Class<?> clazz)74 public GetBundleAction(PackageAdminImpl impl, Class<?> clazz) { 75 this.impl = impl; 76 this.clazz = clazz; 77 } 78 79 @Override run()80 public Bundle run() { 81 return impl.getBundlePriv(clazz); 82 } 83 } 84 85 /** 86 * Constructor. 87 * 88 * @param container the container 89 */ PackageAdminImpl(ModuleContainer container)90 public PackageAdminImpl(ModuleContainer container) { 91 this.container = container; 92 } 93 94 @Override getExportedPackages(Bundle bundle)95 public ExportedPackage[] getExportedPackages(Bundle bundle) { 96 if (bundle == null) { 97 return getExportedPackages((String) null); 98 } 99 Module module = StartLevelImpl.getModule(bundle); 100 Collection<ModuleRevision> revisions = module == null ? Collections.<ModuleRevision> emptyList() : module.getRevisions().getModuleRevisions(); 101 102 Collection<ExportedPackage> allExports = new ArrayList<>(); 103 for (ModuleRevision revision : revisions) { 104 ModuleWiring wiring = revision.getWiring(); 105 if (wiring != null) { 106 List<ModuleCapability> providedPackages = wiring.getModuleCapabilities(PackageNamespace.PACKAGE_NAMESPACE); 107 if (providedPackages != null) { 108 for (ModuleCapability providedPackage : providedPackages) { 109 allExports.add(new ExportedPackageImpl(providedPackage, wiring)); 110 } 111 } 112 } 113 } 114 return allExports.isEmpty() ? null : allExports.toArray(new ExportedPackage[allExports.size()]); 115 } 116 117 @Override getExportedPackage(String name)118 public ExportedPackage getExportedPackage(String name) { 119 ExportedPackage[] allExports = getExportedPackages(name); 120 if (allExports == null) 121 return null; 122 ExportedPackage result = null; 123 for (ExportedPackage allExport : allExports) { 124 if (name.equals(allExport.getName())) { 125 if (result == null) { 126 result = allExport; 127 } else { 128 Version curVersion = result.getVersion(); 129 Version newVersion = allExport.getVersion(); 130 if (newVersion.compareTo(curVersion) >= 0) { 131 result = allExport; 132 } 133 } 134 } 135 } 136 return result; 137 } 138 139 @Override getExportedPackages(String name)140 public ExportedPackage[] getExportedPackages(String name) { 141 String filter = "(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + (name == null ? "*" : name) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$ 142 Map<String, String> directives = Collections.<String, String> singletonMap(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter); 143 Map<String, Boolean> attributes = Collections.singletonMap(Capabilities.SYNTHETIC_REQUIREMENT, Boolean.TRUE); 144 Requirement packageReq = ModuleContainer.createRequirement(PackageNamespace.PACKAGE_NAMESPACE, directives, attributes); 145 Collection<BundleCapability> packageCaps = container.getFrameworkWiring().findProviders(packageReq); 146 InternalUtils.filterCapabilityPermissions(packageCaps); 147 List<ExportedPackage> result = new ArrayList<>(); 148 for (BundleCapability capability : packageCaps) { 149 ModuleWiring wiring = (ModuleWiring) capability.getRevision().getWiring(); 150 if (wiring != null) { 151 Collection<ModuleWiring> wirings = Collections.emptyList(); 152 if ((capability.getRevision().getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) { 153 // This is a fragment, just get all the host wirings 154 List<ModuleWire> hostWires = wiring.getRequiredModuleWires(HostNamespace.HOST_NAMESPACE); 155 if (hostWires != null && !hostWires.isEmpty()) { 156 wirings = new ArrayList<>(hostWires.size()); 157 for (ModuleWire hostWire : hostWires) { 158 ModuleWiring hostWiring = hostWire.getProviderWiring(); 159 if (hostWiring != null) { 160 wirings.add(hostWiring); 161 } 162 } 163 } 164 } else { 165 // just a single host wiring 166 wirings = Collections.singletonList(wiring); 167 } 168 for (ModuleWiring moduleWiring : wirings) { 169 if (!moduleWiring.getSubstitutedNames().contains(capability.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE))) { 170 result.add(new ExportedPackageImpl((ModuleCapability) capability, moduleWiring)); 171 } 172 } 173 } 174 } 175 return (result.size() == 0 ? null : result.toArray(new ExportedPackage[result.size()])); 176 } 177 178 @Override refreshPackages(Bundle[] input)179 public void refreshPackages(Bundle[] input) { 180 container.getFrameworkWiring().refreshBundles(input == null ? null : Arrays.asList(input)); 181 } 182 183 @Override resolveBundles(Bundle[] input)184 public boolean resolveBundles(Bundle[] input) { 185 return container.getFrameworkWiring().resolveBundles(input == null ? null : Arrays.asList(input)); 186 } 187 188 @Override getRequiredBundles(String symbolicName)189 public RequiredBundle[] getRequiredBundles(String symbolicName) { 190 String filter = "(" + BundleNamespace.BUNDLE_NAMESPACE + "=" + (symbolicName == null ? "*" : symbolicName) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$ 191 Map<String, String> directives = Collections.<String, String> singletonMap(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter); 192 Map<String, Boolean> attributes = Collections.singletonMap(Capabilities.SYNTHETIC_REQUIREMENT, Boolean.TRUE); 193 Requirement bundleReq = ModuleContainer.createRequirement(BundleNamespace.BUNDLE_NAMESPACE, directives, attributes); 194 Collection<BundleCapability> bundleCaps = container.getFrameworkWiring().findProviders(bundleReq); 195 InternalUtils.filterCapabilityPermissions(bundleCaps); 196 Collection<RequiredBundle> result = new ArrayList<>(); 197 for (BundleCapability capability : bundleCaps) { 198 BundleWiring wiring = capability.getRevision().getWiring(); 199 if (wiring != null) { 200 result.add(new RequiredBundleImpl(capability, wiring)); 201 } 202 } 203 return result.isEmpty() ? null : result.toArray(new RequiredBundle[result.size()]); 204 } 205 206 @Override getBundles(String symbolicName, String versionRange)207 public Bundle[] getBundles(String symbolicName, String versionRange) { 208 if (symbolicName == null) { 209 throw new IllegalArgumentException(); 210 } 211 if (Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(symbolicName)) { 212 // need to alias system.bundle to the implementation BSN 213 symbolicName = EquinoxContainer.NAME; 214 } 215 VersionRange range = versionRange == null ? null : new VersionRange(versionRange); 216 String filter = (range != null ? "(&" : "") + "(" + IdentityNamespace.IDENTITY_NAMESPACE + "=" + symbolicName + ")" + (range != null ? range.toFilterString(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE) + ")" : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ 217 Requirement identityReq = ModuleContainer.createRequirement(IdentityNamespace.IDENTITY_NAMESPACE, Collections.<String, String> singletonMap(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter), Collections.<String, Object> emptyMap()); 218 Collection<BundleCapability> identityCaps = container.getFrameworkWiring().findProviders(identityReq); 219 220 if (identityCaps.isEmpty()) { 221 return null; 222 } 223 List<Bundle> sorted = new ArrayList<>(identityCaps.size()); 224 for (BundleCapability capability : identityCaps) { 225 Bundle b = capability.getRevision().getBundle(); 226 // a sanity check incase this is an old revision 227 if (symbolicName.equals(b.getSymbolicName()) && !sorted.contains(b)) { 228 sorted.add(b); 229 } 230 } 231 Collections.sort(sorted, new Comparator<Bundle>() { 232 @Override 233 public int compare(Bundle b1, Bundle b2) { 234 return b2.getVersion().compareTo(b1.getVersion()); 235 } 236 }); 237 238 if (sorted.isEmpty()) { 239 return null; 240 } 241 242 return sorted.toArray(new Bundle[sorted.size()]); 243 } 244 245 @Override getFragments(Bundle bundle)246 public Bundle[] getFragments(Bundle bundle) { 247 ModuleWiring wiring = getWiring(bundle); 248 if (wiring == null) { 249 return null; 250 } 251 List<ModuleWire> hostWires = wiring.getProvidedModuleWires(HostNamespace.HOST_NAMESPACE); 252 if (hostWires == null) { 253 // we don't hold locks while checking the graph, just return if no longer valid 254 return null; 255 } 256 Collection<Bundle> fragments = new ArrayList<>(hostWires.size()); 257 for (ModuleWire wire : hostWires) { 258 Bundle fragment = wire.getRequirer().getBundle(); 259 if (fragment != null) { 260 fragments.add(fragment); 261 } 262 } 263 return fragments.isEmpty() ? null : fragments.toArray(new Bundle[fragments.size()]); 264 } 265 266 @Override getHosts(Bundle bundle)267 public Bundle[] getHosts(Bundle bundle) { 268 ModuleWiring wiring = getWiring(bundle); 269 if (wiring == null) { 270 return null; 271 } 272 List<ModuleWire> hostWires = wiring.getRequiredModuleWires(HostNamespace.HOST_NAMESPACE); 273 if (hostWires == null) { 274 // we don't hold locks while checking the graph, just return if no longer valid 275 return null; 276 } 277 Collection<Bundle> hosts = new ArrayList<>(hostWires.size()); 278 for (ModuleWire wire : hostWires) { 279 Bundle host = wire.getProvider().getBundle(); 280 if (host != null) { 281 hosts.add(host); 282 } 283 } 284 return hosts.isEmpty() ? null : hosts.toArray(new Bundle[hosts.size()]); 285 } 286 getWiring(Bundle bundle)287 private ModuleWiring getWiring(Bundle bundle) { 288 Module module = StartLevelImpl.getModule(bundle); 289 if (module == null) { 290 return null; 291 } 292 293 List<ModuleRevision> revisions = module.getRevisions().getModuleRevisions(); 294 if (revisions.isEmpty()) { 295 return null; 296 } 297 298 return revisions.get(0).getWiring(); 299 } 300 getBundlePriv(Class<?> clazz)301 Bundle getBundlePriv(Class<?> clazz) { 302 Bundle b = FrameworkUtil.getBundle(clazz); 303 if (b == null && clazz.getClassLoader() == getClass().getClassLoader()) { 304 return container.getModule(0).getBundle(); 305 } 306 return b; 307 } 308 309 @Override getBundle(final Class<?> clazz)310 public Bundle getBundle(final Class<?> clazz) { 311 if (System.getSecurityManager() == null) 312 return getBundlePriv(clazz); 313 return AccessController.doPrivileged(new GetBundleAction(this, clazz)); 314 } 315 316 @Override getBundleType(Bundle bundle)317 public int getBundleType(Bundle bundle) { 318 Module module = StartLevelImpl.getModule(bundle); 319 if (module == null) { 320 return 0; 321 } 322 List<BundleRevision> revisions = module.getRevisions().getRevisions(); 323 if (revisions.isEmpty()) { 324 return 0; 325 } 326 return (revisions.get(0).getTypes() & BundleRevision.TYPE_FRAGMENT) != 0 ? PackageAdmin.BUNDLE_TYPE_FRAGMENT : 0; 327 } 328 getRemovalPendingBundles()329 public Collection<Bundle> getRemovalPendingBundles() { 330 return container.getFrameworkWiring().getRemovalPendingBundles(); 331 } 332 getDependencyClosure(Collection<Bundle> bundles)333 public Collection<Bundle> getDependencyClosure(Collection<Bundle> bundles) { 334 return container.getFrameworkWiring().getDependencyClosure(bundles); 335 } 336 337 static class ExportedPackageImpl implements ExportedPackage { 338 339 private final ModuleCapability packageCapability; 340 private final ModuleWiring providerWiring; 341 ExportedPackageImpl(ModuleCapability packageCapability, ModuleWiring providerWiring)342 public ExportedPackageImpl(ModuleCapability packageCapability, ModuleWiring providerWiring) { 343 this.packageCapability = packageCapability; 344 this.providerWiring = providerWiring; 345 } 346 347 @Override getName()348 public String getName() { 349 return (String) packageCapability.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE); 350 } 351 352 @Override getExportingBundle()353 public Bundle getExportingBundle() { 354 if (!providerWiring.isInUse()) 355 return null; 356 return providerWiring.getBundle(); 357 } 358 359 @Override getImportingBundles()360 public Bundle[] getImportingBundles() { 361 if (!providerWiring.isInUse()) { 362 return null; 363 } 364 Set<Bundle> importing = new HashSet<>(); 365 366 String packageName = getName(); 367 addRequirers(importing, providerWiring, packageName); 368 369 List<ModuleWire> providedPackages = providerWiring.getProvidedModuleWires(PackageNamespace.PACKAGE_NAMESPACE); 370 if (providedPackages == null) { 371 // we don't hold locks while checking the graph, just return if no longer valid 372 return null; 373 } 374 for (ModuleWire packageWire : providedPackages) { 375 if (packageCapability.equals(packageWire.getCapability())) { 376 importing.add(packageWire.getRequirer().getBundle()); 377 if (packageWire.getRequirerWiring().isSubstitutedPackage(packageName)) { 378 addRequirers(importing, packageWire.getRequirerWiring(), packageName); 379 } 380 } 381 } 382 return importing.toArray(new Bundle[importing.size()]); 383 } 384 addRequirers(Set<Bundle> importing, ModuleWiring wiring, String packageName)385 private static void addRequirers(Set<Bundle> importing, ModuleWiring wiring, String packageName) { 386 List<ModuleWire> requirerWires = wiring.getProvidedModuleWires(BundleNamespace.BUNDLE_NAMESPACE); 387 if (requirerWires == null) { 388 // we don't hold locks while checking the graph, just return if no longer isInUse 389 return; 390 } 391 for (ModuleWire requireBundleWire : requirerWires) { 392 Bundle requirer = requireBundleWire.getRequirer().getBundle(); 393 if (importing.contains(requirer)) { 394 continue; 395 } 396 importing.add(requirer); 397 398 // if reexported then need to add any requirers of the reexporter 399 String reExport = requireBundleWire.getRequirement().getDirectives().get(BundleNamespace.REQUIREMENT_VISIBILITY_DIRECTIVE); 400 ModuleWiring requirerWiring = requireBundleWire.getRequirerWiring(); 401 if (BundleNamespace.VISIBILITY_REEXPORT.equals(reExport)) { 402 addRequirers(importing, requirerWiring, packageName); 403 } 404 // also need to add any importers of the same package as the wiring exports; case of aggregations 405 if (!requirerWiring.equals(wiring)) { 406 List<ModuleWire> providedPackages = requirerWiring.getProvidedModuleWires(PackageNamespace.PACKAGE_NAMESPACE); 407 if (providedPackages != null) { 408 for (ModuleWire packageWire : providedPackages) { 409 if (packageName.equals(packageWire.getCapability().getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE))) { 410 importing.add(packageWire.getRequirer().getBundle()); 411 if (packageWire.getRequirerWiring().isSubstitutedPackage(packageName)) { 412 addRequirers(importing, packageWire.getRequirerWiring(), packageName); 413 } 414 } 415 } 416 } 417 } 418 } 419 } 420 421 /** 422 * @deprecated 423 */ 424 @Override getSpecificationVersion()425 public String getSpecificationVersion() { 426 return getVersion().toString(); 427 } 428 429 @Override getVersion()430 public Version getVersion() { 431 Version version = (Version) packageCapability.getAttributes().get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE); 432 return version == null ? Version.emptyVersion : version; 433 } 434 435 @Override isRemovalPending()436 public boolean isRemovalPending() { 437 return !providerWiring.isCurrent(); 438 } 439 440 @Override toString()441 public String toString() { 442 return packageCapability.toString(); 443 } 444 } 445 446 private static class RequiredBundleImpl implements RequiredBundle { 447 private final BundleCapability bundleCapability; 448 private final BundleWiring providerWiring; 449 RequiredBundleImpl(BundleCapability bundleCapability, BundleWiring providerWiring)450 public RequiredBundleImpl(BundleCapability bundleCapability, BundleWiring providerWiring) { 451 this.bundleCapability = bundleCapability; 452 this.providerWiring = providerWiring; 453 } 454 455 @Override getSymbolicName()456 public String getSymbolicName() { 457 return (String) bundleCapability.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE); 458 } 459 460 @Override getBundle()461 public Bundle getBundle() { 462 if (!providerWiring.isInUse()) 463 return null; 464 return providerWiring.getBundle(); 465 } 466 467 @Override getRequiringBundles()468 public Bundle[] getRequiringBundles() { 469 if (!providerWiring.isInUse()) { 470 return null; 471 } 472 Set<Bundle> requiring = new HashSet<>(); 473 474 addRequirers(requiring, providerWiring); 475 476 return requiring.toArray(new Bundle[requiring.size()]); 477 } 478 addRequirers(Set<Bundle> requiring, BundleWiring providerWiring)479 private static void addRequirers(Set<Bundle> requiring, BundleWiring providerWiring) { 480 List<BundleWire> requirerWires = providerWiring.getProvidedWires(BundleNamespace.BUNDLE_NAMESPACE); 481 if (requirerWires == null) { 482 // we don't hold locks while checking the graph, just return if no longer isInUse 483 return; 484 } 485 for (BundleWire requireBundleWire : requirerWires) { 486 Bundle requirer = requireBundleWire.getRequirer().getBundle(); 487 if (requiring.contains(requirer)) { 488 continue; 489 } 490 requiring.add(requirer); 491 String reExport = requireBundleWire.getRequirement().getDirectives().get(BundleNamespace.REQUIREMENT_VISIBILITY_DIRECTIVE); 492 if (BundleNamespace.VISIBILITY_REEXPORT.equals(reExport)) { 493 addRequirers(requiring, requireBundleWire.getRequirerWiring()); 494 } 495 } 496 } 497 498 @Override getVersion()499 public Version getVersion() { 500 Version version = (Version) bundleCapability.getAttributes().get(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE); 501 return version == null ? Version.emptyVersion : version; 502 } 503 504 @Override isRemovalPending()505 public boolean isRemovalPending() { 506 return !providerWiring.isCurrent(); 507 } 508 509 @Override toString()510 public String toString() { 511 return bundleCapability.toString(); 512 } 513 } 514 } 515