Package org.jnode.plugin.model

Source Code of org.jnode.plugin.model.PluginClassLoaderImpl

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.plugin.model;

import gnu.java.security.action.GetPolicyAction;
import java.net.URL;
import java.nio.ByteBuffer;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.Policy;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.jnode.bootlog.BootLogInstance;
import org.jnode.plugin.PluginClassLoader;
import org.jnode.plugin.PluginDescriptor;
import org.jnode.plugin.PluginException;
import org.jnode.vm.ResourceLoader;
import org.jnode.vm.classmgr.VmClassLoader;

/**
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
final class PluginClassLoaderImpl extends ClassLoader implements PluginClassLoader {

    /**
     * The registry
     */
    private final PluginRegistryModel registry;

    /**
     * The descriptor
     */
    private final PluginDescriptorModel descriptor;

    /**
     * The plugin jar file
     */
    private final PluginJar jar;

    /**
     * The classloaders of the prerequisite plugins
     */
    private final PluginClassLoaderImpl[] prerequisiteLoaders;

    /**
     * Initialize this instance.
     *
     * @param jar
     */
    public PluginClassLoaderImpl(PluginRegistryModel registry,
                                 PluginDescriptorModel descr, PluginJar jar,
                                 PluginClassLoaderImpl[] prerequisiteLoaders) {
        this.registry = registry;
        this.descriptor = descr;
        this.jar = jar;
        this.prerequisiteLoaders = prerequisiteLoaders;
    }

    /**
     * Wrap this {@link ClassLoader} around the given vmClassLoader.
     * Requires special permission.
     *
     * @param vmClassLoader
     * @param registry
     * @param descr
     * @param jar
     * @param prerequisiteLoaders
     */
    protected PluginClassLoaderImpl(VmClassLoader vmClassLoader, PluginRegistryModel registry,
                                    PluginDescriptorModel descr, PluginJar jar,
                                    PluginClassLoaderImpl[] prerequisiteLoaders) {
        super(ClassLoader.getSystemClassLoader(), vmClassLoader);
        this.registry = registry;
        this.descriptor = descr;
        this.jar = jar;
        this.prerequisiteLoaders = prerequisiteLoaders;
    }

    /**
     * Gets the names of the classes contained in this plugin.
     *
     * @return
     */
    public Set<String> getClassNames() {
        HashSet<String> classNames = new HashSet<String>();
        for (String name : jar.resourceNames()) {
            if (name.endsWith(".class")) {
                name = name.substring(0, name.length() - 6);
                classNames.add(name.replace('/', '.'));
            }
        }
        return classNames;
    }

    /**
     * Gets the names of the resources contained in this plugin.
     *
     * @return the set of contained resources
     */
    public Collection<String> getResources() {
        return jar.resourceNames();
    }
   
    /**
     * Finds the specified class. This method should be overridden by class
     * loader implementations that follow the new delegation model for loading
     * classes, and will be called by the loadClass method after checking the
     * parent class loader for the requested class. The default implementation
     * throws ClassNotFoundException.
     *
     * @param name
     * @return Class
     * @throws ClassNotFoundException
     * @see java.lang.ClassLoader#findClass(java.lang.String)
     */
    protected final Class<?> findClass(String name) throws ClassNotFoundException {
        final Class<?> cls = findPluginClass(name);
        if (cls != null) {
            return cls;
        } else {
            // Not found
            throw new ClassNotFoundException(name);
        }
    }

    /**
     * Finds the specified class. This method should be overridden by class
     * loader implementations that follow the new delegation model for loading
     * classes, and will be called by the loadClass method after checking the
     * parent class loader for the requested class. The default implementation
     * throws ClassNotFoundException.
     *
     * @param name
     * @return Class The class, or null if not found.
     * @see java.lang.ClassLoader#findClass(java.lang.String)
     */
    private final Class<?> findPluginClass(String name) {
        // Try the prerequisite loaders first
        final int max = prerequisiteLoaders.length;
        for (int i = 0; i < max; i++) {
            final PluginClassLoaderImpl cl = prerequisiteLoaders[i];
            if (cl != null) {
                final Class<?> cls = cl.findPluginClass(name);
                if (cls != null) {
                    return cls;
                }
            }
        }
        // Try the loaded classes first
        final Class<?> loadedCls = findLoadedClass(name);
        if (loadedCls != null) {
            return loadedCls;
        }

        // Look for it in the fragments
        ByteBuffer b = null;
        FragmentDescriptorModel fragment = null;
        for (FragmentDescriptorModel l : descriptor.fragments()) {
            b = loadClassData(l, name);
            if (b != null) {
                fragment = l;
                break;
            }
        }

        // Look for it in our own jar
        if (b == null) {
            b = loadClassData(jar, name);
        }
        if (b != null) {
            // We're are now going to use one of my classes,
            // so make sure that my plugin has been started.
            try {
                startPlugin();
                if (fragment != null) {
                    fragment.startPlugin(registry);
                }
            } catch (PluginException ex) {
                BootLogInstance.get().error("Error starting plugin", ex);
            }

            // Define package (if needed)
            final int lastDotIndex = name.lastIndexOf('.');
            if (lastDotIndex > 0) {
                String packageName = name.substring(0, lastDotIndex);
                if (getPackage(packageName) == null) {
                    String specTitle = null;
                    String specVendor = null;
                    String specVersion = null;
                    String implTitle = descriptor.getName();
                    String implVendor = descriptor.getProviderName();
                    String implVersion = descriptor.getVersion().toString();
                    URL sealed = null;
                    definePackage(packageName, specTitle, specVendor,
                        specVersion, implTitle, implVendor, implVersion,
                        sealed);
                }
            }

            final URL sourceUrl = jar.getResource(name.replace('.', '/')
                + ".class");
            final CodeSource cs = new CodeSource(sourceUrl, (Certificate[]) null);
            final Policy policy = (Policy) AccessController
                .doPrivileged(GetPolicyAction.getInstance());
            final ProtectionDomain pd = new ProtectionDomain(cs, policy
                .getPermissions(cs));
            final Class<?> cls = defineClass(name, b, pd);
            resolveClass(cls);
            return cls;
        } else {
            return null;
        }
    }

    /**
     * Does this classloader contain the specified class.
     *
     * @return boolean
     */
    protected final boolean containsClass(String name) {
        final String resName = name.replace('.', '/') + ".class";
        if (jar.containsResource(resName)) {
            return true;
        }
        for (ResourceLoader l : descriptor.fragments()) {
            if (l.containsResource(resName)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Finds the resource with the given name. Class loader implementations
     * should override this method to specify where to find resources.
     *
     * @param name
     * @return URL
     * @see java.lang.ClassLoader#findResource(java.lang.String)
     */
    protected final URL findResource(String name) {
        // Try the prerequisite loaders first
        final int max = prerequisiteLoaders.length;
        for (int i = 0; i < max; i++) {
            final PluginClassLoaderImpl cl = prerequisiteLoaders[i];
            if (cl != null) {
                final URL url = cl.findResource(name);
                if (url != null) {
                    return url;
                }
            }
        }

        // Try the fragments
        URL url = null;
        FragmentDescriptorModel fragment = null;
        for (FragmentDescriptorModel f : descriptor.fragments()) {
            url = f.getResource(name);
            if (url != null) {
                fragment = f;
                break;
            }
        }

        // Not found, try my own plugin
        // System.out.println("Try resource " + name + " on " +
        // jar.getDescriptor().getId());
        if (url == null) {
            url = jar.getResource(name);
        }
        if (url != null) {
            try {
                startPlugin();
                if (fragment != null) {
                    fragment.startPlugin(registry);
                }
            } catch (PluginException ex) {
                BootLogInstance.get().error("Cannot start plugin", ex);
            }
        }
        return url;
    }

    public Enumeration<?> getResources(String name) {
        System.err.println("getResources " + name);
        final List<URL> urls = new ArrayList<URL>();

        //
        // Try the prerequisite loaders first
        final int max = prerequisiteLoaders.length;
        for (int i = 0; i < max; i++) {
            final PluginClassLoaderImpl cl = prerequisiteLoaders[i];
            if (cl != null) {
                final URL url = cl.findResource(name);
                if (url != null) {
                    System.err.println("adding " + url);
                    if (!urls.contains(url))
                        urls.add(url);
                }
            }
        }

        // Try the fragments
        URL url = null;
        for (FragmentDescriptorModel fragment : descriptor.fragments()) {
            url = fragment.getResource(name);
            if (url != null) {
                try {
                    startPlugin();
                    fragment.startPlugin(registry);
                } catch (PluginException ex) {
                    BootLogInstance.get().error("Cannot start plugin", ex);
                }
                System.err.println("adding " + url);
                if (!urls.contains(url))
                    urls.add(url);
            }
        }

        // Not found, try my own plugin
        // System.out.println("Try resource " + name + " on " +
        // jar.getDescriptor().getId());
        url = jar.getResource(name);
        if (url != null) {
            try {
                startPlugin();
            } catch (PluginException ex) {
                BootLogInstance.get().error("Cannot start plugin", ex);
            }
            System.err.println("adding " + url);
            if (!urls.contains(url))
                urls.add(url);
        }
        //

        return new Enumeration<URL>() {
            private Iterator<URL> it = urls.iterator();

            public boolean hasMoreElements() {
                return it.hasNext();
            }

            public URL nextElement() {
                return it.next();
            }
        };
    }

    /**
     * Try to load the data of a class with a given name.
     *
     * @param name
     * @return The loaded class data or null if not found.
     */
    private final ByteBuffer loadClassData(ResourceLoader loader, String name) {
        return loader.getResourceAsBuffer(name.replace('.', '/') + ".class");
    }

    /**
     * Make sure that the plugin gets started. This method ensures that this
     * classloader can be used to start the plugin.
     */
    private final void startPlugin() throws PluginException {
        descriptor.startPlugin(registry);
    }

    /**
     * @see org.jnode.plugin.PluginClassLoader#getDeclaringPluginDescriptor()
     */
    public PluginDescriptor getDeclaringPluginDescriptor() {
        return descriptor;
    }
       
    public String toString() {
        return getClass().getName() + '(' + getDeclaringPluginDescriptor().getId() + ')';
    }   
}
TOP

Related Classes of org.jnode.plugin.model.PluginClassLoaderImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.