All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tuscany.sca.extensibility.ClassLoaderContext Maven / Gradle / Ivy

There is a newer version: 2.0.1
Show newest version
/*
 * 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 delegates) {
        List loaders = new ArrayList(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 doPrivileged(PrivilegedAction 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 doPrivileged(PrivilegedExceptionAction 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 getClassLoaders(ServiceDiscovery discovery, String... serviceNames) {
        List loaders = new ArrayList();
        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 getClassLoaders(ServiceDiscovery discovery, Class... serviceTypes) {
        List loaders = new ArrayList();
        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 findResources(String name) throws IOException {
            return sd.getResources(name);
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy