Conceptual flaw in wiring to non-osgi modules
thomas.diesler May 30, 2012 3:49 AMThere is likely a conceptual flaw in the way we handle Resources/BundleRevision for non-osgi modules. This thread is related to
* AS7-4915 ClassCastException - AbstractResource cannot be cast to AbstractBundleRevision
* AS7-4918 Registered module using OSGi capability not visible as a bundle
Currently there are two places when we register a module with the resolver environment
#1 AutoInstallIntegration.installInitialModuleCapability(OSGiCapability osgicap)
// Attempt to load the module from the modules hierarchy Module module = null; try { ModuleLoader moduleLoader = Module.getBootModuleLoader(); module = moduleLoader.loadModule(moduleId); } catch (ModuleLoadException ex) { throw MESSAGES.startFailedCannotResolveInitialCapability(ex, identifier); } if (module != null) { OSGiMetaData metadata = getModuleMetadata(module); XResourceBuilder builder = XResourceBuilderFactory.create(); if (metadata != null) { builder.loadFrom(metadata); } else { builder.loadFrom(module); } XResource res = builder.getResource(); res.addAttachment(Module.class, module); injectedEnvironment.getValue().installResources(res); return true; }
#2 ModuleRegisterProcessor.ModuleRegisterService.start(StartContext context)
LOGGER.tracef("Starting: %s in mode %s", controller.getName(), controller.getMode()); LOGGER.infoRegisterModule(module); try { XResourceBuilder builder = XResourceBuilderFactory.create(); if (metadata != null) { builder.loadFrom(metadata); } else { builder.loadFrom(module); } resource = builder.getResource(); resource.addAttachment(Module.class, module); injectedEnvironment.getValue().installResources(resource); } catch (Throwable th) { throw MESSAGES.startFailedToRegisterModule(th, module); }
The code is very similar and in both cases we create a Resource with associated Capabilities/Requirements. Note, this is a org.osgi.resource.Resource and not a org.osgi.framework.wiring.BundleRevision
As a result the BundleManagerPlugin needs to filter the registered resources in all variants of getBundle
Set<Bundle> getBundles() { Set<Bundle> result = new HashSet<Bundle>(); XEnvironment env = injectedEnvironment.getValue(); for (Resource aux : env.getResources(IDENTITY_TYPES)) { if (aux instanceof AbstractBundleRevision) { AbstractBundleRevision brev = (AbstractBundleRevision) aux; AbstractBundleState bundleState = brev.getBundleState(); if (bundleState.getState() != Bundle.UNINSTALLED) result.add(bundleState); } } return Collections.unmodifiableSet(result); }
Registered modules have hence no Bundle API view.
When a bundle gets resolved it may get wired to package capability provided by a registered module. There is no restriction on the resource type and a Wiring will get created for a given Resource. In various place the framework assumes that a resource that is associated with a given Capability/Requirement is a org.osgi.framework.wiring.BundleRevision rather than a plain org.osgi.resource.Resource which causes the CCE reported in AS7-4915
java.lang.ClassCastException: org.jboss.osgi.resolver.spi.AbstractResource cannot be cast to org.jboss.osgi.framework.internal.AbstractBundleRevision at org.jboss.osgi.framework.internal.PackageAdminPlugin$ExportedPackageImpl.getImportingBundles(PackageAdminPlugin.java:536) at org.apache.felix.webconsole.internal.core.BundlesServlet.listImportExport(BundlesServlet.java:813)
There are potentially several approaches to fix this
#1 Drop wires to non-osgi modules from the wiring API. Module dependencies would still be created but not visible through public API (i.e. PackageAdmin and later the R5 Wiring API). Non-osgi modules don't show up as bundles in the framework.
#2 Always create BundleRevisions with associated BundleCapabilities/BundleRequirements. Non-osgi modules would be managed by the framework as fabricated bundles. Some Bundle API would not be supported. The framework management view would potentially show a large set of bundles which are in fact not bundles.
#3 Lazy transformation from Resource to BundleRevision when a Resource is choosen as a wire target. As above, non-osgi modules would be managed by the framework as fabricated bundles. Some Bundle API would not be supported. Framework management view would only show bundles which are either real bundles or non-osgi bundles that take part in the wiring.
Thoughts?