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/06 15:14:04 UTC

svn commit: r1042653 - in /incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly: ./ api/

Author: davidb
Date: Mon Dec  6 14:14:03 2010
New Revision: 1042653

URL: http://svn.apache.org/viewvc?rev=1042653&view=rev
Log:
Work in progress.

Added:
    incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/MultiDelegationClassloader.java
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/MyWeavingHook.java
    incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/SPIBundleTrackerCustomizer.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/Util.java
    incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/api/SpiFlyConstants.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=1042653&r1=1042652&r2=1042653&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 Mon Dec  6 14:14:03 2010
@@ -18,8 +18,12 @@
  */
 package org.apache.aries.spifly;
 
+import java.util.Collection;
 import java.util.List;
+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;
@@ -39,6 +43,9 @@ 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>>();
+
     public synchronized void start(BundleContext context) throws Exception {
         lst = new LogServiceTracker(context);
         lst.open();
@@ -94,4 +101,14 @@ public class Activator implements Bundle
             logServices.remove(service);
         }        
     }
+
+    public void registerSPIProviderBundle(String registrationClassName, Bundle bundle) {
+        registeredSPIs.putIfAbsent(registrationClassName, new CopyOnWriteArraySet<Bundle>());
+        Collection<Bundle> bl = registeredSPIs.get(registrationClassName);
+        bl.add(bundle);
+    }
+
+    public Collection<Bundle> findSPIProviderBundles(String name) {
+        return registeredSPIs.get(name);
+    }
 }

Added: incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/MultiDelegationClassloader.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/MultiDelegationClassloader.java?rev=1042653&view=auto
==============================================================================
--- incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/MultiDelegationClassloader.java (added)
+++ incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/MultiDelegationClassloader.java Mon Dec  6 14:14:03 2010
@@ -0,0 +1,81 @@
+/**
+ * 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.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+
+public class MultiDelegationClassloader extends ClassLoader {
+    private final ClassLoader[] delegates;
+    
+    public MultiDelegationClassloader(ClassLoader ... classLoaders) {
+        if (classLoaders == null) 
+            throw new NullPointerException();
+        
+        delegates = classLoaders.clone();
+    }
+    
+    @Override
+    public URL getResource(String name) {
+        for (ClassLoader cl : delegates) {
+            URL res = cl.getResource(name);
+            if (res != null)
+                return res;
+        }                
+        return null;
+    }
+    
+    @Override
+    public InputStream getResourceAsStream(String name) {
+        for (ClassLoader cl : delegates) {
+            InputStream is = cl.getResourceAsStream(name);
+            if (is != null)
+                return is;
+        }
+        return null;
+    }
+    
+    @Override
+    public Enumeration<URL> getResources(String name) throws IOException {
+        List<URL> urls = new ArrayList<URL>();
+        
+        for (ClassLoader cl : delegates) {
+            urls.addAll(Collections.list(cl.getResources(name)));
+        }
+        return Collections.enumeration(urls);
+    }
+    
+    @Override
+    public Class<?> loadClass(String name) throws ClassNotFoundException {
+        ClassNotFoundException lastEx = null;
+        for (ClassLoader cl : delegates) {
+            try {
+                return cl.loadClass(name);
+            } catch (ClassNotFoundException e) {
+                lastEx = e;
+            }
+        }
+        throw lastEx;
+    }
+}

Modified: incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/MyWeavingHook.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/MyWeavingHook.java?rev=1042653&r1=1042652&r2=1042653&view=diff
==============================================================================
--- incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/MyWeavingHook.java (original)
+++ incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/MyWeavingHook.java Mon Dec  6 14:14:03 2010
@@ -18,12 +18,14 @@
  */
 package org.apache.aries.spifly;
 
+import org.apache.aries.spifly.api.SpiFlyConstants;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassWriter;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.hooks.weaving.WeavingHook;
 import org.osgi.framework.hooks.weaving.WovenClass;
+import org.osgi.service.log.LogService;
 
 public class MyWeavingHook implements WeavingHook {
     private final String addedImport;
@@ -40,9 +42,8 @@ public class MyWeavingHook implements We
     
 	@Override
 	public void weave(WovenClass wovenClass) {
-	    // TODO base this on SPI-Consumer header
-	    if (wovenClass.getBundleWiring().getBundle().getSymbolicName().equals("MyTestBundle"))
-	    {
+	    if (wovenClass.getBundleWiring().getBundle().getHeaders().get(SpiFlyConstants.SPI_CONSUMER_HEADER) != null) {
+	        Activator.activator.log(LogService.LOG_DEBUG, "Weaving class " + wovenClass.getClassName());
 	        System.out.println("*** WovenClass: " + wovenClass.getClassName());
 	        
 	        ClassReader cr = new ClassReader(wovenClass.getBytes());

Modified: incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/SPIBundleTrackerCustomizer.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/SPIBundleTrackerCustomizer.java?rev=1042653&r1=1042652&r2=1042653&view=diff
==============================================================================
--- incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/SPIBundleTrackerCustomizer.java (original)
+++ incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/SPIBundleTrackerCustomizer.java Mon Dec  6 14:14:03 2010
@@ -25,10 +25,7 @@ import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.List;
-import java.util.StringTokenizer;
 
-import org.apache.aries.spifly.HeaderParser.PathElement;
-import org.apache.aries.spifly.api.SPIClassloaderAdviceService;
 import org.apache.aries.spifly.api.SpiFlyConstants;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleEvent;
@@ -43,6 +40,9 @@ public class SPIBundleTrackerCustomizer 
     public SPIBundleTrackerCustomizer(Activator a, Bundle b) {
         activator = a;
         spiBundle = b;
+        
+        
+        // TODO handle pre-existing bundles.
     }
 
     public List<ServiceRegistration<?>> addingBundle(Bundle bundle, BundleEvent event) {
@@ -97,12 +97,15 @@ public class SPIBundleTrackerCustomizer 
                 ServiceRegistration<?> reg = bundle.getBundleContext()
                         .registerService(registrationClassName, o, props);
                 registrations.add(reg);
-                log(LogService.LOG_INFO, "Registered service: " + reg);
+
+                activator.registerSPIProviderBundle(registrationClassName, bundle);
+                log(LogService.LOG_INFO, "Registered service: " + reg);                
             } catch (Exception e) {
                 log(LogService.LOG_WARNING,
                         "Could not load SPI implementation referred from " + url, e);
             }
         }
+        
 
         /*
         // the new approach - services are being registered based on contents of
@@ -197,21 +200,6 @@ public class SPIBundleTrackerCustomizer 
         }
     }
 
-    private String trimQuotes(String input) {
-        if (input == null) {
-            return input;
-        }
-        if (input.startsWith("\"")) {
-            input = input.substring(1);
-        }
-
-        if (input.endsWith("\"")) {
-            input = input.substring(0, input.length() - 1);
-        }
-
-        return input;
-    }
-
     private void log(int level, String message) {
         activator.log(level, message);
     }

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=1042653&r1=1042652&r2=1042653&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 Mon Dec  6 14:14:03 2010
@@ -28,7 +28,7 @@ import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 
 public class TCCLSetterVisitor extends ClassAdapter implements ClassVisitor, Opcodes {
-    private static final String GENERATED_METHOD_NAME = "$$fixContextClassLoader$$";
+    private static final String GENERATED_METHOD_NAME = "$$FCCL$$";
 
     private static final String UTIL_CLASS = Util.class.getName().replace('.', '/'); 
     private static final String VOID_RETURN_TYPE = "()V";
@@ -48,54 +48,88 @@ public class TCCLSetterVisitor extends C
         MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
         return new TCCLSetterMethodVisitor(mv);
     }
-    
+
     @Override
     public void visitEnd() {
         // Add generated static method
-        MethodVisitor mv = cv.visitMethod(ACC_PRIVATE + ACC_STATIC,
-                GENERATED_METHOD_NAME, "()V", null, null);
+
+        /* Equivalent to:
+         * private static void SomeMethodName(Class<?> cls) {
+         *   Util.fixContextClassLoader("java.util.ServiceLoader", "load", cls, WovenClass.class.getClassLoader());
+         * }
+         */
+        MethodVisitor mv = cv.visitMethod(ACC_PRIVATE + ACC_STATIC, GENERATED_METHOD_NAME, 
+                "(Ljava/lang/Class;)V", "(Ljava/lang/Class<*>;)V", null);
         mv.visitCode();
         mv.visitLdcInsn("java.util.ServiceLoader");
         mv.visitLdcInsn("load");
+        mv.visitVarInsn(ALOAD, 0);
         String typeIdentifier = "L" + targetClass + ";";
         mv.visitLdcInsn(Type.getType(typeIdentifier));
         mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class",
                 "getClassLoader", "()Ljava/lang/ClassLoader;");
-        mv.visitMethodInsn(INVOKESTATIC, "org/apache/aries/spifly/Util",
+        mv.visitMethodInsn(
+                INVOKESTATIC,
+                "org/apache/aries/spifly/Util",
                 "fixContextClassloader",
-                "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");
+                "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/ClassLoader;)V");
         mv.visitInsn(RETURN);
-        mv.visitMaxs(3, 0);
+        mv.visitMaxs(4, 1);
         mv.visitEnd();
-        
+
         super.visitEnd();
     }
     
-
-
     private class TCCLSetterMethodVisitor extends MethodAdapter implements MethodVisitor
     {
+        Type lastLDCType;
+        
         public TCCLSetterMethodVisitor(MethodVisitor mv) {
             super(mv);
         }
 
+        
+        /**
+         * Store the last LDC call. When ServiceLoader.load(Class cls) is called
+         * the last LDC call before the ServiceLoader.load() visitMethodInsn call
+         * contains the class being passed in. We need to pass this class to $$FCCL$$ as well
+         * so we can copy the value found in here.
+         */
+        @Override
+        public void visitLdcInsn(Object cst) {
+            if (cst instanceof Type) {
+                lastLDCType = ((Type) cst);
+            }
+            super.visitLdcInsn(cst);
+        }
+
+        /**
+         * Wrap selected method calls with
+         *  Util.storeContextClassloader();
+         *  $$FCCL$$(<class>)
+         *  Util.restoreContextClassloader(); 
+         */
         @Override
-        public void visitMethodInsn(int opcode, String owner, String name,
-                String desc) {
+        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
             System.out.println("### " + opcode + ": " + owner + "#" + name + "#" + desc);
             
             if (opcode == INVOKESTATIC &&
                 "java/util/ServiceLoader".equals(owner) &&
                 "load".equals(name)) {
                 System.out.println("+++ Gotcha!");
-                                
+          
+                // 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.
+                mv.visitLdcInsn(lastLDCType);
                 mv.visitMethodInsn(INVOKESTATIC, targetClass,
-                        GENERATED_METHOD_NAME, VOID_RETURN_TYPE);
+                        GENERATED_METHOD_NAME, "(Ljava/lang/Class;)V");
 
                 super.visitMethodInsn(opcode, owner, name, desc);
 
+                // Add: Util.restoreContextClassloader();
                 mv.visitMethodInsn(INVOKESTATIC, UTIL_CLASS,
                         "restoreContextClassloader", VOID_RETURN_TYPE);
             } else {                

Modified: incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/Util.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/Util.java?rev=1042653&r1=1042652&r2=1042653&view=diff
==============================================================================
--- incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/Util.java (original)
+++ incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/Util.java Mon Dec  6 14:14:03 2010
@@ -18,45 +18,65 @@
  */
 package org.apache.aries.spifly;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
 import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleReference;
 import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.service.log.LogService;
 
+/** 
+ * Methods used from ASM-generated code. They store, change and reset the thread context classloader.
+ * The methods are static to make it easy to access them from generated code.
+ */
 public class Util {
-    static ThreadLocal<ClassLoader> classLoaders = new ThreadLocal<ClassLoader>();
+    static ThreadLocal<ClassLoader> storedClassLoaders = new ThreadLocal<ClassLoader>();
     
     public static void storeContextClassloader() {
-        classLoaders.set(Thread.currentThread().getContextClassLoader());
+        storedClassLoaders.set(Thread.currentThread().getContextClassLoader());
     }
     
     public static void restoreContextClassloader() {
-        Thread.currentThread().setContextClassLoader(classLoaders.get());
-        classLoaders.set(null);
+        Thread.currentThread().setContextClassLoader(storedClassLoaders.get());
+        storedClassLoaders.set(null);
     }
-    
-    public static void fixContextClassloader(String cls, String method, ClassLoader loader) {
-        System.out.println("~~~ cls: " + cls + " method: " + method + " cl:" + loader);
         
-        Thread.currentThread().setContextClassLoader(findClassLoader());
+    public static void fixContextClassloader(String cls, String method, Class<?> clsArg, ClassLoader bundleLoader) {
+        System.out.println("~~~ cls: " + cls + " method: " + method + " clarg:" + clsArg + " cl:" + bundleLoader);
+        
+        ClassLoader cl = findClassloader(clsArg);
+        if (cl != null) {
+            Activator.activator.log(LogService.LOG_INFO, "Temporarily setting Thread Context Classloader to: " + cl);
+            Thread.currentThread().setContextClassLoader(cl);
+        } else {
+            Activator.activator.log(LogService.LOG_WARNING, "No classloader found for " + cls + ":" + method + "(" + clsArg + ")");
+        }
     }
     
-    private static ClassLoader findClassLoader() {
-//        Activator.activator.getClassloaderAdvice()
+    private static ClassLoader findClassloader(Class<?> cls) {
+        Activator activator = Activator.activator;
+        
+        Collection<Bundle> bundles = activator.findSPIProviderBundles(cls.getName());
+        activator.log(LogService.LOG_DEBUG, "Found bundles providing " + cls + ": " + bundles);
         
-        ClassLoader cl = Activator.class.getClassLoader();
-        if (!(cl instanceof BundleReference)) {
+        if (bundles == null)
             return null;
-        }
         
-        BundleReference br = (BundleReference) cl;      
-        for (Bundle b : br.getBundle().getBundleContext().getBundles()) {
-            // TODO find the appropriate bundle
-            if ("MyServiceImpl".equals(b.getSymbolicName())) {
+        switch (bundles.size()) {
+        case 0:
+            return null;
+        case 1:
+            Bundle bundle = bundles.iterator().next();
+            BundleWiring wiring = bundle.adapt(BundleWiring.class);
+            return wiring.getClassLoader();            
+        default:
+            List<ClassLoader> loaders = new ArrayList<ClassLoader>();
+            for (Bundle b : bundles) {
                 BundleWiring bw = b.adapt(BundleWiring.class);
-                if (bw != null)
-                    return bw.getClassLoader();
-            }           
+                loaders.add(bw.getClassLoader());
+            }
+            return new MultiDelegationClassloader(loaders.toArray(new ClassLoader[loaders.size()]));
         }
-        return null;
     }
 }

Modified: incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/api/SpiFlyConstants.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/api/SpiFlyConstants.java?rev=1042653&r1=1042652&r2=1042653&view=diff
==============================================================================
--- incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/api/SpiFlyConstants.java (original)
+++ incubator/aries/trunk/spi-fly/contrib/pilot_using_weavinghook/SpiFly/src/org/apache/aries/spifly/api/SpiFlyConstants.java Mon Dec  6 14:14:03 2010
@@ -19,37 +19,8 @@
 package org.apache.aries.spifly.api;
 
 public interface SpiFlyConstants {
-
-    /*
-     * Header names
-     */
-
     String SPI_CONSUMER_HEADER = "SPI-Consumer";
-
     String SPI_PROVIDER_HEADER = "SPI-Provider";
 
-    /*
-     * Attributes to be used with the SPI-Provider and SPI-Consumer headers
-     */
-
-    String PROVIDER_NAME_ATTRIBUTE = "provider-name";
-
-    String SERVICE_IDS_ATTRIBUTE = "service-ids";
-
-    /*
-     * Attributes to be used with services created using the 'old' approach
-     */
-
     String SPI_PROVIDER_URL = "spi.provider.url";
-
-    /*
-     * Attributes to be used with services created using the 'new' approach
-     */
-
-    String SERVICE_ID_SERVICE_ATTRIBUTE = "ServiceId";
-
-    String PROVIDER_NAME_SERVICE_ATTRIBUTE = "ProviderName";
-
-    String API_NAME_SERVICE_ATTRIBUTE = "ApiName";
-
 }