| /* |
| * 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.tuscany.sca.extensibility; |
| |
| import java.io.IOException; |
| import java.net.URL; |
| import java.security.PrivilegedAction; |
| import java.security.PrivilegedActionException; |
| import java.security.PrivilegedExceptionAction; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Enumeration; |
| import java.util.List; |
| |
| import org.apache.tuscany.sca.extensibility.impl.ClassLoaderDelegate; |
| |
| /** |
| * A utility that controls context class loaders |
| * @tuscany.spi.extension.asclient |
| */ |
| public class ClassLoaderContext { |
| private ClassLoader classLoader; |
| |
| /** |
| * Create a context with the parent classloader and a list of service types that can be discovered |
| * by the {@link ServiceDiscovery} |
| * @param parent |
| * @param discovery |
| * @param serviceTypes |
| */ |
| public ClassLoaderContext(ClassLoader parent, ServiceDiscovery discovery, Class<?>... serviceTypes) { |
| this(parent, getClassLoaders(discovery, serviceTypes)); |
| } |
| |
| private ClassLoaderContext(ClassLoader parent, List<ClassLoader> delegates) { |
| List<ClassLoader> loaders = new ArrayList<ClassLoader>(delegates); |
| loaders.remove(parent); |
| if (delegates.isEmpty()) { |
| classLoader = parent; |
| } else { |
| classLoader = new ClassLoaderDelegate(parent, loaders); |
| } |
| } |
| |
| /** |
| * Create a context that is visible to the parent classloader as well as the list of classloaders |
| * @param parent |
| * @param delegates |
| */ |
| public ClassLoaderContext(ClassLoader parent, ClassLoader... delegates) { |
| this(parent, Arrays.asList(delegates)); |
| } |
| |
| /** |
| * Create a context with the parent classloader and a list of service types that can be discovered |
| * by the {@link ServiceDiscovery} |
| * @param parent |
| * @param discovery |
| * @param serviceTypes |
| */ |
| public ClassLoaderContext(ClassLoader parent, ServiceDiscovery discovery, String... serviceTypes) { |
| this(parent, getClassLoaders(discovery, serviceTypes)); |
| } |
| |
| public <T> T doPrivileged(PrivilegedAction<T> action) { |
| ClassLoader tccl = Thread.currentThread().getContextClassLoader(); |
| if (tccl != classLoader) { |
| Thread.currentThread().setContextClassLoader(classLoader); |
| } |
| try { |
| return action.run(); |
| } finally { |
| if (tccl != classLoader) { |
| Thread.currentThread().setContextClassLoader(tccl); |
| } |
| } |
| } |
| |
| public <T> T doPrivileged(PrivilegedExceptionAction<T> action) throws PrivilegedActionException { |
| ClassLoader tccl = Thread.currentThread().getContextClassLoader(); |
| if (tccl != classLoader) { |
| Thread.currentThread().setContextClassLoader(classLoader); |
| } |
| try { |
| return action.run(); |
| } catch (Exception e) { |
| throw new PrivilegedActionException(e); |
| } finally { |
| if (tccl != classLoader) { |
| Thread.currentThread().setContextClassLoader(tccl); |
| } |
| } |
| } |
| |
| /** |
| * Set the thread context classloader (TCCL) to a classloader that delegates to a collection |
| * of classloaders |
| * @param parent The parent classloader |
| * @param delegates A list of classloaders to try |
| * @return The existing TCCL |
| */ |
| public static ClassLoader setContextClassLoader(ClassLoader parent, ClassLoader... delegates) { |
| ClassLoaderContext context = new ClassLoaderContext(parent, delegates); |
| return context.setContextClassLoader(); |
| } |
| |
| /** |
| * Set the context classloader so that it can access the list of service providers |
| * @param parent The parent classloader |
| * @param serviceNames A list of service provider names |
| * @return The old TCCL if a new one is set, otherwise null |
| */ |
| public static ClassLoader setContextClassLoader(ClassLoader parent, |
| ServiceDiscovery discovery, |
| String... serviceNames) { |
| ClassLoaderContext context = new ClassLoaderContext(parent, discovery, serviceNames); |
| return context.setContextClassLoader(); |
| } |
| |
| /** |
| * Set the context classloader so that it can access the list of service providers |
| * @param parent The parent classloader |
| * @param serviceNames A list of service provider names |
| * @return The old TCCL if a new one is set, otherwise null |
| */ |
| public static ClassLoader setContextClassLoader(ClassLoader parent, |
| ServiceDiscovery discovery, |
| Class<?>... serviceTypes) { |
| ClassLoaderContext context = new ClassLoaderContext(parent, discovery, serviceTypes); |
| return context.setContextClassLoader(); |
| } |
| |
| public ClassLoader setContextClassLoader() { |
| ClassLoader tccl = Thread.currentThread().getContextClassLoader(); |
| if (tccl != classLoader) { |
| Thread.currentThread().setContextClassLoader(classLoader); |
| return tccl; |
| } else { |
| return null; |
| } |
| } |
| |
| private static ClassLoader getClassLoader(ServiceDiscovery discovery, String serviceProvider) { |
| try { |
| ServiceDeclaration sd = discovery.getServiceDeclaration(serviceProvider); |
| if (sd != null) { |
| try { |
| if (sd.loadClass() != null) { |
| return sd.loadClass().getClassLoader(); |
| } else { |
| return new ClassLoaderImpl(sd); |
| } |
| } catch (ClassNotFoundException e) { |
| return new ClassLoaderImpl(sd); |
| } |
| } |
| } catch (Exception e) { |
| // Ignore |
| } |
| return null; |
| } |
| |
| private static List<ClassLoader> getClassLoaders(ServiceDiscovery discovery, String... serviceNames) { |
| List<ClassLoader> loaders = new ArrayList<ClassLoader>(); |
| for (String sp : serviceNames) { |
| ClassLoader loader = getClassLoader(discovery, sp); |
| if (loader != null) { |
| if (!loaders.contains(loader)) { |
| loaders.add(loader); |
| } |
| } |
| } |
| ClassLoader tccl = discovery.getContextClassLoader(); |
| if (!loaders.contains(tccl)) { |
| loaders.add(tccl); |
| } |
| return loaders; |
| } |
| |
| private static ClassLoader getClassLoader(ServiceDiscovery discovery, Class<?> serviceType) { |
| try { |
| ServiceDeclaration sd = discovery.getServiceDeclaration(serviceType); |
| if (sd != null) { |
| return sd.loadClass().getClassLoader(); |
| } |
| } catch (Exception e) { |
| // Ignore |
| } |
| return null; |
| } |
| |
| private static List<ClassLoader> getClassLoaders(ServiceDiscovery discovery, Class<?>... serviceTypes) { |
| List<ClassLoader> loaders = new ArrayList<ClassLoader>(); |
| for (Class<?> serviceType : serviceTypes) { |
| ClassLoader classLoader = getClassLoader(discovery, serviceType); |
| if (classLoader != null && !loaders.contains(classLoader)) { |
| loaders.add(classLoader); |
| } |
| } |
| ClassLoader tccl = discovery.getContextClassLoader(); |
| if (!loaders.contains(tccl)) { |
| loaders.add(tccl); |
| } |
| return loaders; |
| } |
| |
| public ClassLoader getClassLoader() { |
| return classLoader; |
| } |
| |
| private static class ClassLoaderImpl extends ClassLoader { |
| private final ServiceDeclaration sd; |
| |
| public ClassLoaderImpl(ServiceDeclaration sd) { |
| super(); |
| this.sd = sd; |
| } |
| |
| @Override |
| protected Class<?> findClass(String name) throws ClassNotFoundException { |
| return sd.loadClass(name); |
| } |
| |
| @Override |
| protected URL findResource(String name) { |
| return sd.getResource(name); |
| } |
| |
| @Override |
| protected Enumeration<URL> findResources(String name) throws IOException { |
| return sd.getResources(name); |
| } |
| |
| } |
| |
| } |