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";
-
}