You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by da...@apache.org on 2010/12/14 16:54:45 UTC
svn commit: r1049137 - in
/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook:
SpiFly/src/org/apache/aries/spifly/ SpiFlyTests/src/org/apache/aries/spifly/
Author: davidb
Date: Tue Dec 14 15:54:45 2010
New Revision: 1049137
URL: http://svn.apache.org/viewvc?rev=1049137&view=rev
Log:
Test covering multiple suitable providers for ServiceLoader.load()
Modified:
incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/Activator.java
incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/ProviderBundleTrackerCustomizer.java
incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/ClientWeavingHookTest.java
Modified: incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/Activator.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/Activator.java?rev=1049137&r1=1049136&r2=1049137&view=diff
==============================================================================
--- incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/Activator.java (original)
+++ incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/Activator.java Tue Dec 14 15:54:45 2010
@@ -21,10 +21,11 @@ package org.apache.aries.spifly;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.CopyOnWriteArraySet;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
@@ -44,8 +45,8 @@ public class Activator implements Bundle
private List<LogService> logServices = new CopyOnWriteArrayList<LogService>();
private BundleTracker<List<ServiceRegistration<?>>> bt;
- private final ConcurrentMap<String, Collection<Bundle>>registeredSPIs =
- new ConcurrentHashMap<String, Collection<Bundle>>();
+ private final ConcurrentMap<String, SortedMap<Long, Bundle>>registeredSPIs =
+ new ConcurrentHashMap<String, SortedMap<Long, Bundle>>();
public synchronized void start(BundleContext context) throws Exception {
lst = new LogServiceTracker(context);
@@ -103,14 +104,14 @@ public class Activator implements Bundle
}
}
- public void registerSPIProviderBundle(String registrationClassName, Bundle bundle) {
- registeredSPIs.putIfAbsent(registrationClassName, new CopyOnWriteArraySet<Bundle>());
- Collection<Bundle> bl = registeredSPIs.get(registrationClassName);
- bl.add(bundle);
+ public void registerSPIProviderBundle(String registrationClassName, Bundle bundle) {
+ registeredSPIs.putIfAbsent(registrationClassName, Collections.synchronizedSortedMap(new TreeMap<Long, Bundle>()));
+ SortedMap<Long, Bundle> map = registeredSPIs.get(registrationClassName);
+ map.put(bundle.getBundleId(), bundle);
}
public Collection<Bundle> findSPIProviderBundles(String name) {
- Collection<Bundle> bundles = registeredSPIs.get(name);
- return bundles == null ? Collections.<Bundle>emptyList() : bundles;
+ SortedMap<Long, Bundle> map = registeredSPIs.get(name);
+ return map == null ? Collections.<Bundle>emptyList() : map.values();
}
}
Modified: incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/ProviderBundleTrackerCustomizer.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/ProviderBundleTrackerCustomizer.java?rev=1049137&r1=1049136&r2=1049137&view=diff
==============================================================================
--- incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/ProviderBundleTrackerCustomizer.java (original)
+++ incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/ProviderBundleTrackerCustomizer.java Tue Dec 14 15:54:45 2010
@@ -106,88 +106,11 @@ public class ProviderBundleTrackerCustom
}
}
-
- /*
- // the new approach - services are being registered based on contents of
- // the SPI-Provider header
- if (bundleClassloader == null) {
- log(LogService.LOG_INFO, "Unable to identify classloader. "
- + "Skipping SPIClassloaderAdviceService(s) registeration.");
- } else {
-
- // Register SPIClassloaderAdviceService services for APIs mentioned
- // in the header
- String spiProviderHeader = (String) bundle.getHeaders().get(
- SpiFlyConstants.SPI_PROVIDER_HEADER);
- List<PathElement> parsedHeader = HeaderParser
- .parseHeader(spiProviderHeader);
- for (PathElement pe : parsedHeader) {
-
- // Format of each path element:
- // api1Name;provider-name="myimpl2";service-ids="myserviceId"
-
- // An example below.
- // Please note:
- // 1. The service-ids attribute holds a list of ids that will be
- // used when searching META-INF/services/. In other words
- // this will be the name of the class that will be passed to
- // ServiceLoader.load().
- // 2. A single bundle can provide implementations for many APIs
- // - there might be many api names in a single SPI-Provider
- // header.
-
- // Sample:
- // jaxb;provider-name="xerces123";service-ids="javax.xml.bind.JAXBContext"
-
- // the clause begins with a name of the API for which this
- // bundle provides an impl
- String apiName = pe.getName();
- // unique name of the provider
- String providerName = pe
- .getAttribute(SpiFlyConstants.PROVIDER_NAME_ATTRIBUTE);
- providerName = trimQuotes(providerName);
-
- //
- String serviceIds = pe
- .getAttribute(SpiFlyConstants.SERVICE_IDS_ATTRIBUTE);
- serviceIds = trimQuotes(serviceIds);
-
- if (apiName == null || providerName == null
- || serviceIds == null) {
- log(LogService.LOG_INFO, "Skipping: " + apiName + " "
- + providerName + " " + serviceIds
- + ". Null values are not allowed.");
- }
-
- StringTokenizer tokenizer = new StringTokenizer(serviceIds, ",");
- while (tokenizer.hasMoreTokens()) {
- String serviceId = tokenizer.nextToken().trim();
- SPIClassloaderAdviceServiceImpl service = new SPIClassloaderAdviceServiceImpl(
- bundleClassloader);
- Hashtable<String, Object> props = new Hashtable<String, Object>();
- props.put(SpiFlyConstants.API_NAME_SERVICE_ATTRIBUTE,
- apiName);
- props.put(SpiFlyConstants.PROVIDER_NAME_SERVICE_ATTRIBUTE,
- providerName);
- props.put(SpiFlyConstants.SERVICE_ID_SERVICE_ATTRIBUTE,
- serviceId);
- ServiceRegistration reg = bundle
- .getBundleContext()
- .registerService(
- SPIClassloaderAdviceService.class.getName(),
- service, props);
- registrations.add(reg);
- log(LogService.LOG_INFO, "Registered service: " + reg);
- }
- }
-
- } */
-
return registrations;
}
public void modifiedBundle(Bundle bundle, BundleEvent event, List<ServiceRegistration<?>> registrations) {
- // nothing to do here
+ // should really be doing something here...
}
public void removedBundle(Bundle bundle, BundleEvent event, List<ServiceRegistration<?>> registrations) {
Modified: incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/ClientWeavingHookTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/ClientWeavingHookTest.java?rev=1049137&r1=1049136&r2=1049137&view=diff
==============================================================================
--- incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/ClientWeavingHookTest.java (original)
+++ incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/ClientWeavingHookTest.java Tue Dec 14 15:54:45 2010
@@ -32,60 +32,108 @@ public class ClientWeavingHookTest {
@Test
public void testClientWeavingHookBasicServiveLoaderUsage() throws Exception {
- // Set up the classloader that will be used by the ASM-generated code as the TCCL.
- // It can load a META-INF/services file
- ClassLoader cl = new TestImplClassLoader("impl1", "META-INF/services/org.apache.aries.mytest.MySPI");
-
- // The BundleWiring API is used on the bundle by the generated code to obtain its classloader
- BundleWiring bw = EasyMock.createMock(BundleWiring.class);
- EasyMock.expect(bw.getClassLoader()).andReturn(cl);
- EasyMock.replay(bw);
-
- // Create a mock object for the client bundle which holds the code that uses ServiceLoader.load().
- Bundle testBundle = EasyMock.createMock(Bundle.class);
- EasyMock.expect(testBundle.getSymbolicName()).andReturn("mytestbundle");
- EasyMock.expect(testBundle.getVersion()).andReturn(Version.parseVersion("1.2.3"));
+ BundleContext spiFlyBundleContext = mockSpiFlyBundle("spifly", Version.parseVersion("1.9.4"));
+
Dictionary<String, String> headers = new Hashtable<String, String>();
headers.put(SpiFlyConstants.SPI_CONSUMER_HEADER, "true");
- EasyMock.expect(testBundle.getHeaders()).andReturn(headers);
- EasyMock.expect(testBundle.adapt(BundleWiring.class)).andReturn(bw);
- EasyMock.replay(testBundle);
-
- BundleContext bc = EasyMock.createMock(BundleContext.class);
- EasyMock.expect(bc.getBundle()).andReturn(testBundle);
- EasyMock.replay(bc);
-
- WeavingHook wh = new ClientWeavingHook(bc);
+ Bundle consumerBundle = mockConsumerBundle(headers);
+
+ WeavingHook wh = new ClientWeavingHook(spiFlyBundleContext);
// Weave the TestClient class.
URL clsUrl = getClass().getResource("TestClient.class");
Assert.assertNotNull("precondition", clsUrl);
- WovenClass wc = new MyWovenClass(clsUrl, "org.apache.aries.spifly.TestClient", testBundle);
+ WovenClass wc = new MyWovenClass(clsUrl, "org.apache.aries.spifly.TestClient", consumerBundle);
Assert.assertEquals("Precondition", 0, wc.getDynamicImports().size());
wh.weave(wc);
Assert.assertEquals(1, wc.getDynamicImports().size());
- String di1 = "org.apache.aries.spifly;bundle-symbolic-name=mytestbundle;bundle-version=1.2.3";
- String di2 = "org.apache.aries.spifly;bundle-version=1.2.3;bundle-symbolic-name=mytestbundle";
+ String di1 = "org.apache.aries.spifly;bundle-symbolic-name=spifly;bundle-version=1.9.4";
+ String di2 = "org.apache.aries.spifly;bundle-version=1.9.4;bundle-symbolic-name=spifly";
String di = wc.getDynamicImports().get(0);
Assert.assertTrue("Weaving should have added a dynamic import", di1.equals(di) || di2.equals(di));
-
+
// ok the weaving is done, now prepare the registry for the call
- Activator.activator.registerSPIProviderBundle("org.apache.aries.mytest.MySPI", testBundle);
+ Bundle providerBundle = mockProviderBundle("impl1", 1, "META-INF/services/org.apache.aries.mytest.MySPI");
+ Activator.activator.registerSPIProviderBundle("org.apache.aries.mytest.MySPI", providerBundle);
// Invoke the woven class and check that it propertly sets the TCCL so that the
// META-INF/services/org.apache.aries.mytest.MySPI file from impl1 is visible.
Class<?> cls = wc.getDefinedClass();
- Object inst = cls.newInstance();
Method method = cls.getMethod("test", new Class [] {String.class});
- Object result = method.invoke(inst, "hello");
+ Object result = method.invoke(cls.newInstance(), "hello");
Assert.assertEquals("olleh", result);
}
-
+
@Test
public void testClientWeavingHookMultipleProviders() throws Exception {
+ BundleContext spiFlyBundleContext = mockSpiFlyBundle("spifly", Version.parseVersion("1.9.4"));
+ Dictionary<String, String> headers = new Hashtable<String, String>();
+ headers.put(SpiFlyConstants.SPI_CONSUMER_HEADER, "true");
+ Bundle consumerBundle = mockConsumerBundle(headers);
+
+ WeavingHook wh = new ClientWeavingHook(spiFlyBundleContext);
+
+ // Weave the TestClient class.
+ URL clsUrl = getClass().getResource("TestClient.class");
+ WovenClass wc = new MyWovenClass(clsUrl, "org.apache.aries.spifly.TestClient", consumerBundle);
+ Assert.assertEquals("Precondition", 0, wc.getDynamicImports().size());
+ wh.weave(wc);
+
+ Bundle providerBundle1 = mockProviderBundle("impl1", 1, "META-INF/services/org.apache.aries.mytest.MySPI");
+ Bundle providerBundle2 = mockProviderBundle("impl2", 2, "META-INF/services/org.apache.aries.mytest.MySPI");
+
+ // Register in reverse order to make sure the order in which bundles are sorted is correct
+ Activator.activator.registerSPIProviderBundle("org.apache.aries.mytest.MySPI", providerBundle2);
+ Activator.activator.registerSPIProviderBundle("org.apache.aries.mytest.MySPI", providerBundle1);
+
+ // Invoke the woven class and check that it propertly sets the TCCL so that the
+ // META-INF/services/org.apache.aries.mytest.MySPI files from impl1 and impl2 are visible.
+ Class<?> cls = wc.getDefinedClass();
+ Method method = cls.getMethod("test", new Class [] {String.class});
+ Object result = method.invoke(cls.newInstance(), "hello");
+ Assert.assertEquals("All three services should be invoked in the correct order", "ollehHELLO5", result);
+ }
+
+ private BundleContext mockSpiFlyBundle(String bsn, Version version) {
+ Bundle spiFlyBundle = EasyMock.createMock(Bundle.class);
+ EasyMock.expect(spiFlyBundle.getSymbolicName()).andReturn(bsn);
+ EasyMock.expect(spiFlyBundle.getVersion()).andReturn(version);
+ EasyMock.replay(spiFlyBundle);
+
+ BundleContext spiFlyBundleContext = EasyMock.createMock(BundleContext.class);
+ EasyMock.expect(spiFlyBundleContext.getBundle()).andReturn(spiFlyBundle);
+ EasyMock.replay(spiFlyBundleContext);
+ return spiFlyBundleContext;
+ }
+
+ private Bundle mockProviderBundle(String subdir, long id, String ... resources) {
+ // Set up the classloader that will be used by the ASM-generated code as the TCCL.
+ // It can load a META-INF/services file
+ ClassLoader cl = new TestImplClassLoader(subdir, resources);
+
+ // The BundleWiring API is used on the bundle by the generated code to obtain its classloader
+ BundleWiring bw = EasyMock.createMock(BundleWiring.class);
+ EasyMock.expect(bw.getClassLoader()).andReturn(cl);
+ EasyMock.replay(bw);
+
+ Bundle providerBundle = EasyMock.createMock(Bundle.class);
+ EasyMock.expect(providerBundle.adapt(BundleWiring.class)).andReturn(bw);
+ EasyMock.expect(providerBundle.getBundleId()).andReturn(id);
+ EasyMock.replay(providerBundle);
+ return providerBundle;
}
+
+ private Bundle mockConsumerBundle(Dictionary<String, String> headers) {
+ // Create a mock object for the client bundle which holds the code that uses ServiceLoader.load().
+ Bundle consumerBundle = EasyMock.createMock(Bundle.class);
+
+ EasyMock.expect(consumerBundle.getHeaders()).andReturn(headers);
+ EasyMock.replay(consumerBundle);
+ return consumerBundle;
+ }
+
private class TestImplClassLoader extends URLClassLoader {
private final List<String> resources;
private final String prefix;