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/21 09:05:16 UTC

svn commit: r1051409 - in /incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook: SpiFly/src/org/apache/aries/spifly/ SpiFlyTests/src/org/apache/aries/spifly/ SpiFlyTests/src/org/apache/aries/spifly/impl4/ SpiFlyTests/src/org/apache/aries/spifl...

Author: davidb
Date: Tue Dec 21 08:05:15 2010
New Revision: 1051409

URL: http://svn.apache.org/viewvc?rev=1051409&view=rev
Log:
Ability to deal with distinguishing overloads, e.g. ServiceLoader.load(Class) != ServiceLoader.load(Class, ClassLoader)

Added:
    incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/UnaffectedTestClient.java
    incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/impl4/
    incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/impl4/META-INF/
    incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/impl4/META-INF/services/
    incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/impl4/META-INF/services/org.apache.aries.mytest.MySPI
    incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/impl4/MySPIImpl4.java
Modified:
    incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/ClientWeavingHook.java
    incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/TCCLSetterVisitor.java
    incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/WeavingData.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/ClientWeavingHook.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/ClientWeavingHook.java?rev=1051409&r1=1051408&r2=1051409&view=diff
==============================================================================
--- incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/ClientWeavingHook.java (original)
+++ incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/ClientWeavingHook.java Tue Dec 21 08:05:15 2010
@@ -19,7 +19,6 @@
 package org.apache.aries.spifly;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 import java.util.ServiceLoader;
 
@@ -58,12 +57,21 @@ public class ClientWeavingHook implement
 	        ClassReader cr = new ClassReader(wovenClass.getBytes());
 	        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
 	        TCCLSetterVisitor tsv = new TCCLSetterVisitor(cw, wovenClass.getClassName(), wd);
-	        cr.accept(tsv, 0);
+	        cr.accept(tsv, 0);	        
 	        wovenClass.setBytes(cw.toByteArray());
-	        wovenClass.getDynamicImports().add(addedImport);
+	        if (tsv.additionalImportRequired())
+	            wovenClass.getDynamicImports().add(addedImport);
 	    }			
 	}
 
+	/**
+	 * Parses headers of the following syntax:
+	 * <ul>
+	 * </ul>
+	 * @param consumerBundle
+	 * @param consumerHeader
+	 * @return
+	 */
     private WeavingData parseHeader(Bundle consumerBundle, String consumerHeader) {
         List<Bundle> selectedBundles = new ArrayList<Bundle>();
 
@@ -71,22 +79,37 @@ public class ClientWeavingHook implement
             String name = element.getName().trim();
             String className;
             String methodName;
+            String[] argClasses;
             int hashIdx = name.indexOf('#');
             if (hashIdx > 0) {
                 className = name.substring(0, hashIdx);
                 int braceIdx = name.substring(hashIdx).indexOf('(');
                 if (braceIdx > 0) {
                     methodName = name.substring(hashIdx + 1, hashIdx + braceIdx);
+                    int closeIdx = name.substring(hashIdx).indexOf(')');
+                    if (closeIdx > 0) {
+                        String classes = name.substring(hashIdx + braceIdx + 1, hashIdx + closeIdx).trim();
+                        if (classes.length() > 0) {
+                            argClasses = classes.split(",");
+                        } else { 
+                            argClasses = null;
+                        }
+                    } else {
+                        argClasses = null;
+                    }
                 } else {
-                    methodName = name.substring(hashIdx + 1);                    
+                    methodName = name.substring(hashIdx + 1);
+                    argClasses = null;
                 }
             } else {
                 if ("true".equalsIgnoreCase(name)) {
                     className = ServiceLoader.class.getName();
                     methodName = "load";
+                    argClasses = new String [] { Class.class.getName() };
                 } else {
                     className = name;
                     methodName = null;
+                    argClasses = null; 
                 }
             }            
                 
@@ -118,7 +141,7 @@ public class ClientWeavingHook implement
                 Activator.activator.registerConsumerBundle(consumerBundle, selectedBundles);
            
             // TODO support more than one definition
-            return new WeavingData(className, methodName, 1);
+            return new WeavingData(className, methodName, argClasses);
         }
         return null;
     }

Modified: incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/TCCLSetterVisitor.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/TCCLSetterVisitor.java?rev=1051409&r1=1051408&r2=1051409&view=diff
==============================================================================
--- incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/TCCLSetterVisitor.java (original)
+++ incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/TCCLSetterVisitor.java Tue Dec 21 08:05:15 2010
@@ -41,6 +41,10 @@ public class TCCLSetterVisitor extends C
     private final String targetClass;
     private final WeavingData weavingData;
 
+    // Set to true when the weaving code has changed the client such that an additional import 
+    // (to the Util.class.getPackage()) is needed.
+    private boolean additionalImportRequired = false;
+
     public TCCLSetterVisitor(ClassVisitor cv, String className, WeavingData weavingData) {
         super(cv);
         this.targetClass = className.replace('.', '/');
@@ -119,22 +123,37 @@ public class TCCLSetterVisitor extends C
         public void visitMethodInsn(int opcode, String owner, String name, String desc) {
             System.out.println("### " + opcode + ": " + owner + "#" + name + "#" + desc);
             
+            Type[] argTypes = Type.getArgumentTypes(desc);
+            String [] argClassNames = new String[argTypes.length];
+            for (int i = 0; i < argTypes.length; i++) {
+                argClassNames[i] = argTypes[i].getClassName();
+            }
+            
             if (opcode == INVOKESTATIC &&
                 weavingData.getClassName().replace('.', '/').equals(owner) &&
-                weavingData.getMethodName().equals(name)) {
+                weavingData.getMethodName().equals(name) && 
+                (weavingData.getArgClasses() != null ? Arrays.equals(argClassNames, weavingData.getArgClasses()) : true)) {
                 System.out.println("+++ Gotcha!");
           
+                additionalImportRequired = true;
+
                 // Add: Util.storeContextClassloader();                
                 mv.visitMethodInsn(INVOKESTATIC, UTIL_CLASS,
                         "storeContextClassloader", VOID_RETURN_TYPE);
-                // Add: MyClass.$$FCCL$$(<class>);
-                
-                // The class is the same class as the one passed into the ServiceLoader.load() api.
+
+                // Add: MyClass.$$FCCL$$(<class>);                
                 if (ServiceLoader.class.getName().equals(weavingData.getClassName()) &&
-                    "load".equals(weavingData.getMethodName())) {
+                    "load".equals(weavingData.getMethodName()) &&
+                    Arrays.equals(new String [] {Class.class.getName()}, weavingData.getArgClasses())) {
+                    // ServiceLoader.load() is a special case because it's a general-purpose service loader, 
+                    // therefore, the target class it the class being passed in to the ServiceLoader.load() 
+                    // call itself.
                     mv.visitLdcInsn(lastLDCType);
                 } else {
-                    Type type = Type.getType("L" + owner + ";");
+                    // In any other case, we're not dealing with a general-purpose service loader, but rather
+                    // with a specific one, such as DocumentBuilderFactory.newInstance(). In that case the 
+                    // target class is the class that is being invoked on (i.e. DocumentBuilderFactory).
+                    Type type = Type.getObjectType(owner);
                     mv.visitLdcInsn(type);
                 }
                 mv.visitMethodInsn(INVOKESTATIC, targetClass,
@@ -150,4 +169,8 @@ public class TCCLSetterVisitor extends C
             }
         }
     }
+
+    public boolean additionalImportRequired() {
+        return additionalImportRequired ;
+    }
 }

Modified: incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/WeavingData.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/WeavingData.java?rev=1051409&r1=1051408&r2=1051409&view=diff
==============================================================================
--- incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/WeavingData.java (original)
+++ incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/WeavingData.java Tue Dec 21 08:05:15 2010
@@ -1,18 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 package org.apache.aries.spifly;
 
-import java.util.List;
-
-import org.osgi.framework.Bundle;
-
 public class WeavingData {
     private final String className;
     private final String methodName;
-    private final int argCount;
+    private final String[] argClasses;
     
-    public WeavingData(String className, String methodName, int argCount) {
+    public WeavingData(String className, String methodName, String[] argClasses2) {
         this.className = className;
         this.methodName = methodName;
-        this.argCount = argCount;
+        this.argClasses = argClasses2;
     }
 
     public String getClassName() {
@@ -23,7 +37,7 @@ public class WeavingData {
         return methodName;
     }
 
-    public int getArgCount() {
-        return argCount;
+    public String[] getArgClasses() {
+        return argClasses;
     }
 }

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=1051409&r1=1051408&r2=1051409&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 21 08:05:15 2010
@@ -43,7 +43,7 @@ public class ClientWeavingHookTest {
         
         // Weave the TestClient class.
         URL clsUrl = getClass().getResource("TestClient.class");
-        Assert.assertNotNull("precondition", clsUrl);
+        Assert.assertNotNull("Precondition", clsUrl);
         WovenClass wc = new MyWovenClass(clsUrl, "org.apache.aries.spifly.TestClient", consumerBundle);
         Assert.assertEquals("Precondition", 0, wc.getDynamicImports().size());
         wh.weave(wc);
@@ -66,6 +66,38 @@ public class ClientWeavingHookTest {
     }
 
     @Test
+    public void testClientWeavingHookAltServiceLoaderLoadUnprocessed() throws Exception {
+        Bundle spiFlyBundle = mockSpiFlyBundle();               
+       
+        Dictionary<String, String> headers = new Hashtable<String, String>();
+        headers.put(SpiFlyConstants.SPI_CONSUMER_HEADER, "true");
+        Bundle consumerBundle = mockConsumerBundle(headers, spiFlyBundle);
+
+        WeavingHook wh = new ClientWeavingHook(spiFlyBundle.getBundleContext());
+        
+        // Weave the TestClient class.
+        URL clsUrl = getClass().getResource("UnaffectedTestClient.class");
+        Assert.assertNotNull("Precondition", clsUrl);
+        WovenClass wc = new MyWovenClass(clsUrl, "org.apache.aries.spifly.UnaffectedTestClient", consumerBundle);
+        Assert.assertEquals("Precondition", 0, wc.getDynamicImports().size());
+        wh.weave(wc);
+
+        Assert.assertEquals("The client is not affected so no additional imports should have been added", 
+            0, wc.getDynamicImports().size());
+                
+        // ok the weaving is done, now prepare the registry for the call
+        Bundle providerBundle = mockProviderBundle("impl1", 1, "META-INF/services/org.apache.aries.mytest.MySPI");        
+        Activator.activator.registerProviderBundle("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();
+        Method method = cls.getMethod("test", new Class [] {String.class});
+        Object result = method.invoke(cls.newInstance(), "hello");
+        Assert.assertEquals("impl4", result);
+    }
+
+    @Test
     public void testClientWeavingHookMultipleProviders() throws Exception {
         Bundle spiFlyBundle = mockSpiFlyBundle();
 
@@ -121,12 +153,7 @@ public class ClientWeavingHookTest {
         Object result = method.invoke(cls.newInstance(), "hello");
         Assert.assertEquals("Only the services from bundle impl2 should be selected", "HELLO5", result);        
     }
-    
-    @Test
-    public void testServiceProviderOverloadUnprocessed() {
-        Assert.fail("Test that ServiceLoader.load(2) doesn't get affected");
-    }
-    
+        
     @Test
     public void testJAXPClientWantsJREImplementation1() throws Exception {
         Bundle systembundle = mockSystemBundle();
@@ -285,7 +312,7 @@ public class ClientWeavingHookTest {
         return systemBundle;
     }
             
-    private class TestImplClassLoader extends URLClassLoader {
+    public static class TestImplClassLoader extends URLClassLoader {
         private final List<String> resources;
         private final String prefix;
         

Added: incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/UnaffectedTestClient.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/UnaffectedTestClient.java?rev=1051409&view=auto
==============================================================================
--- incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/UnaffectedTestClient.java (added)
+++ incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/UnaffectedTestClient.java Tue Dec 21 08:05:15 2010
@@ -0,0 +1,18 @@
+package org.apache.aries.spifly;
+
+import java.util.ServiceLoader;
+
+import org.apache.aries.mytest.MySPI;
+
+public class UnaffectedTestClient {
+    public String test(String input) {
+        StringBuilder sb = new StringBuilder();
+        
+        ServiceLoader<MySPI> loader = ServiceLoader.load(MySPI.class,
+            new ClientWeavingHookTest.TestImplClassLoader("impl4", "META-INF/services/org.apache.aries.mytest.MySPI"));
+        for (MySPI mySPI : loader) {
+            sb.append(mySPI.someMethod(input));
+        }
+        return sb.toString();
+    }
+}

Added: incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/impl4/META-INF/services/org.apache.aries.mytest.MySPI
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/impl4/META-INF/services/org.apache.aries.mytest.MySPI?rev=1051409&view=auto
==============================================================================
--- incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/impl4/META-INF/services/org.apache.aries.mytest.MySPI (added)
+++ incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/impl4/META-INF/services/org.apache.aries.mytest.MySPI Tue Dec 21 08:05:15 2010
@@ -0,0 +1,2 @@
+org.apache.aries.spifly.impl4.MySPIImpl4
+

Added: incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/impl4/MySPIImpl4.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/impl4/MySPIImpl4.java?rev=1051409&view=auto
==============================================================================
--- incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/impl4/MySPIImpl4.java (added)
+++ incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFlyTests/src/org/apache/aries/spifly/impl4/MySPIImpl4.java Tue Dec 21 08:05:15 2010
@@ -0,0 +1,10 @@
+package org.apache.aries.spifly.impl4;
+
+import org.apache.aries.mytest.MySPI;
+
+public class MySPIImpl4 implements MySPI {
+    @Override
+    public String someMethod(String s) {
+        return "impl4";
+    }
+}