ProviderBundleTrackerCustomizer implements BundleTrackerCustomizer { @Override public List<ServiceRegistration> addingBundle(final Bundle bundle, BundleEvent event) { BundleRevision bundleRevision = bundle.adapt(BundleRevision.class); if (bundle.equals(spiBundle) || ((bundleRevision != null) && ((bundleRevision.getTypes() & TYPE_FRAGMENT) == TYPE_FRAGMENT))) return null; log(Level.FINE, "Bundle Considered for SPI providers: " + bundle.getSymbolicName()); DiscoveryMode discoveryMode = DiscoveryMode.SERVICELOADER_CAPABILITIES; List<String> providedServices = null; Map<String, Object> customAttributes = new HashMap<String, Object>(); if (bundle.getHeaders().get(SpiFlyConstants.REQUIRE_CAPABILITY) != null) { try { providedServices = readServiceLoaderMediatorCapabilityMetadata(bundle, customAttributes); } catch (InvalidSyntaxException e) { log(Level.FINE, "Unable to read capabilities from bundle " + bundle, e); } } String spiProviderHeader = getHeaderFromBundleOrFragment(bundle, SpiFlyConstants.SPI_PROVIDER_HEADER); if (providedServices == null && spiProviderHeader != null) { String header = spiProviderHeader.trim(); if ("*".equals(header)) { providedServices = new ArrayList<String>(); } else { providedServices = Stream.of(header.split(",")).map(String::trim).collect(toList()); } discoveryMode = DiscoveryMode.SPI_PROVIDER_HEADER; } List<URL> serviceFileURLs = null; if (providedServices == null) { Entry<List<String>, List<URL>> autoServices = getFromAutoProviderProperty(bundle, customAttributes); providedServices = autoServices.getKey(); serviceFileURLs = autoServices.getValue(); discoveryMode = DiscoveryMode.AUTO_PROVIDERS_PROPERTY; } if (providedServices == null) { log(Level.FINE, "No provided SPI services. Skipping bundle: " + bundle.getSymbolicName()); return null; } else { log(Level.FINE, "Examining bundle for SPI provider: " + bundle.getSymbolicName()); } for (String serviceType : providedServices) { activator.registerProviderBundle(serviceType, bundle, customAttributes); } if (serviceFileURLs == null) { serviceFileURLs = getServiceFileUrls(bundle); } final List<ServiceRegistration> registrations = new ArrayList<ServiceRegistration>(); for (ServiceDetails details : collectServiceDetails(bundle, serviceFileURLs, discoveryMode)) { if (providedServices.size() > 0 && !providedServices.contains(details.serviceType)) continue; try { final Class<?> cls = bundle.loadClass(details.instanceType); log(Level.FINE, "Loaded SPI provider: " + cls); if (details.properties != null) { ServiceRegistration reg = null; Object instance = (details.properties.containsKey("service.scope") && "prototype".equalsIgnoreCase(String.valueOf(details.properties.get("service.scope")))) ? new ProviderPrototypeServiceFactory(cls) : new ProviderServiceFactory(cls); SecurityManager sm = System.getSecurityManager(); if (sm != null) { if (bundle.hasPermission(new ServicePermission(details.serviceType, ServicePermission.REGISTER))) { reg = bundle.getBundleContext().registerService( details.serviceType, instance, details.properties); } else { log(Level.FINE, "Bundle " + bundle + " does not have the permission to register services of type: " + details.serviceType); } } else { reg = bundle.getBundleContext().registerService( details.serviceType, instance, details.properties); } if (reg != null) { registrations.add(reg); log(Level.FINE, "Registered service: " + reg); } } activator.registerProviderBundle(details.serviceType, bundle, details.properties); log(Level.INFO, "Registered provider " + details.instanceType + " of service " + details.serviceType + " in bundle " + bundle.getSymbolicName()); } catch (Exception e) { log(Level.FINE, "Could not load provider " + details.instanceType + " of service " + details.serviceType, e); } } return registrations; } ProviderBundleTrackerCustomizer(BaseActivator activator, Bundle spiBundle); @Override List<ServiceRegistration> addingBundle(final Bundle bundle, BundleEvent event); @Override void modifiedBundle(Bundle bundle, BundleEvent event, Object registrations); @Override @SuppressWarnings("unchecked") void removedBundle(Bundle bundle, BundleEvent event, Object registrations);  }
@Test public void testAddingBundleSPIBundle() throws Exception { BundleContext implBC = mockSPIBundleContext(EasyMock.createNiceMock(ServiceRegistration.class)); Bundle spiBundle = mockSPIBundle(implBC); ProviderBundleTrackerCustomizer customizer = new ProviderBundleTrackerCustomizer(activator, spiBundle); assertNull("The SpiFly bundle itself should be ignored", customizer.addingBundle(spiBundle, null)); }
@Test public void testAddingNonOptInBundle() throws Exception { BundleContext implBC = mockSPIBundleContext(EasyMock.createNiceMock(ServiceRegistration.class)); Bundle implBundle = mockSPIBundle(implBC, null); ProviderBundleTrackerCustomizer customizer = new ProviderBundleTrackerCustomizer(activator, null); assertNull("Bundle doesn't opt-in so should be ignored", customizer.addingBundle(implBundle, null)); }
@Test @SuppressWarnings("unchecked") public void testAddingBundleWithBundleClassPath() throws Exception { Bundle mediatorBundle = EasyMock.createMock(Bundle.class); EasyMock.expect(mediatorBundle.getBundleId()).andReturn(42l).anyTimes(); EasyMock.replay(mediatorBundle); ProviderBundleTrackerCustomizer customizer = new ProviderBundleTrackerCustomizer(activator, mediatorBundle); BundleContext implBC = EasyMock.createMock(BundleContext.class); EasyMock.<Object>expect(implBC.registerService( EasyMock.eq("org.apache.aries.mytest.MySPI"), EasyMock.isA(ServiceFactory.class), (Dictionary<String,?>) EasyMock.anyObject())).andReturn(EasyMock.createNiceMock(ServiceRegistration.class)).times(3); EasyMock.replay(implBC); Bundle implBundle = EasyMock.createNiceMock(Bundle.class); EasyMock.expect(implBundle.getBundleContext()).andReturn(implBC).anyTimes(); Dictionary<String, String> headers = new Hashtable<String, String>(); headers.put(SpiFlyConstants.SPI_PROVIDER_HEADER, "*"); headers.put(Constants.BUNDLE_CLASSPATH, ".,non-jar.jar,embedded.jar,embedded2.jar"); EasyMock.expect(implBundle.getHeaders()).andReturn(headers).anyTimes(); URL embeddedJar = getClass().getResource("/embedded.jar"); assertNotNull("precondition", embeddedJar); EasyMock.expect(implBundle.getResource("embedded.jar")).andReturn(embeddedJar).anyTimes(); URL embedded2Jar = getClass().getResource("/embedded2.jar"); assertNotNull("precondition", embedded2Jar); EasyMock.expect(implBundle.getResource("embedded2.jar")).andReturn(embedded2Jar).anyTimes(); URL dir = new URL("jar:" + embeddedJar + "!/META-INF/services"); assertNotNull("precondition", dir); EasyMock.expect(implBundle.getResource("/META-INF/services")).andReturn(dir).anyTimes(); EasyMock.expect(implBundle.findEntries((String) EasyMock.anyObject(), (String) EasyMock.anyObject(), EasyMock.anyBoolean())). andReturn(null).anyTimes(); ClassLoader cl = new URLClassLoader(new URL [] {embeddedJar}, getClass().getClassLoader()); Class<?> clsA = cl.loadClass("org.apache.aries.spifly.impl2.MySPIImpl2a"); EasyMock.<Object>expect(implBundle.loadClass("org.apache.aries.spifly.impl2.MySPIImpl2a")).andReturn(clsA).anyTimes(); Class<?> clsB = cl.loadClass("org.apache.aries.spifly.impl2.MySPIImpl2b"); EasyMock.<Object>expect(implBundle.loadClass("org.apache.aries.spifly.impl2.MySPIImpl2b")).andReturn(clsB).anyTimes(); ClassLoader cl2 = new URLClassLoader(new URL [] {embedded2Jar}, getClass().getClassLoader()); Class<?> clsC = cl2.loadClass("org.apache.aries.spifly.impl3.MySPIImpl3"); EasyMock.<Object>expect(implBundle.loadClass("org.apache.aries.spifly.impl3.MySPIImpl3")).andReturn(clsC).anyTimes(); EasyMock.replay(implBundle); assertEquals("Precondition", 0, activator.findProviderBundles("org.apache.aries.mytest.MySPI").size()); List<ServiceRegistration> registrations = customizer.addingBundle(implBundle, null); Collection<Bundle> bundles = activator.findProviderBundles("org.apache.aries.mytest.MySPI"); assertEquals(1, bundles.size()); assertSame(implBundle, bundles.iterator().next()); EasyMock.verify(implBC); }
@Test public void testMultipleProviderServices() throws Exception { BundleContext implBC = mockSPIBundleContext(EasyMock.createNiceMock(ServiceRegistration.class)); Bundle implBundle = mockMultiSPIBundle(implBC); Bundle spiBundle = EasyMock.createNiceMock(Bundle.class); EasyMock.expect(spiBundle.getBundleId()).andReturn(25l).anyTimes(); EasyMock.replay(spiBundle); ProviderBundleTrackerCustomizer customizer = new ProviderBundleTrackerCustomizer(activator, spiBundle); assertEquals(2, customizer.addingBundle(implBundle, null).size()); }