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;