君子博学而日参省乎己 则知明而行无过矣

博客园 首页 新随笔 联系 订阅 管理

插件工厂类PluginFactory.java

/**
 * Constellio, Open Source Enterprise Search
 * Copyright (C) 2010 DocuLibre inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program 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 distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package com.doculibre.constellio.plugins;

import java.io.File;
import java.io.FileFilter;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import net.xeoh.plugins.base.PluginManager;
import net.xeoh.plugins.base.impl.PluginManagerFactory;
import net.xeoh.plugins.base.impl.PluginManagerImpl;
import net.xeoh.plugins.base.impl.classpath.ClassPathManager;
import net.xeoh.plugins.base.impl.classpath.ClassPathManagerUtils;
import net.xeoh.plugins.base.util.PluginManagerUtil;

import org.apache.commons.io.FileUtils;

import com.doculibre.constellio.plugins.api.ConstellioPlugin;
import com.doculibre.constellio.plugins.defaults.DefaultConstellioPlugin;
import com.doculibre.constellio.utils.ClasspathUtils;
import com.doculibre.constellio.utils.ConstellioSpringUtils;

public class PluginFactory {

    private static Set<ClassLoader> classLoaders = new HashSet<ClassLoader>();

    private static PluginManager pm;

    @SuppressWarnings("unchecked")
    private static void initPluginManager() {
        if (pm == null) {
            pm = PluginManagerFactory.createPluginManager();
            File classesDir = ClasspathUtils.getClassesDir();

            pm.addPluginsFrom(classesDir.toURI());

            File pluginsDir = getPluginsDir();
            File[] pluginDirs = pluginsDir.listFiles(new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    boolean accept;
                    if (pathname.isFile()) {
                        accept = false;
                    } else if (DefaultConstellioPlugin.NAME.equals(pathname)) {
                        accept = true;
                    } else {
                        List<String> availablePluginNames = ConstellioSpringUtils.getAvailablePluginNames();
                        accept = availablePluginNames.contains(pathname.getName());
                    }
                    return accept;
                }
            });
            for (File pluginDir : pluginDirs) {
                // Plugin root dir jars
                Collection<File> pluginJarFiles = FileUtils.listFiles(pluginDir, new String[] { "jar" },
                    false);
                // Accept only one root dir jar
                File pluginJarFile = pluginJarFiles.isEmpty() ? null : pluginJarFiles.iterator().next();
                if (pluginJarFile != null) {
                    URI pluginJarFileURI = pluginJarFile.toURI();
                    pm.addPluginsFrom(pluginJarFileURI);

                    PluginManagerImpl pmImpl = (PluginManagerImpl) pm;
                    ClassPathManager classPathManager = pmImpl.getClassPathManager();
                    ClassLoader classLoader = ClassPathManagerUtils.getClassLoader(classPathManager,
                        pluginJarFile);
                    classLoaders.add(classLoader);

                    File pluginLibDir = new File(pluginDir, "lib");
                    if (pluginLibDir.exists() && pluginLibDir.isDirectory()) {
                        Collection<File> pluginDependencies = FileUtils.listFiles(pluginLibDir,
                            new String[] { "jar" }, false);
                        ClassPathManagerUtils.addJarDependencies(classPathManager, pluginJarFile,
                            pluginDependencies);
                    }
                }
            }
        }
    }

    public static <P extends ConstellioPlugin> P getPlugin(Class<P> pluginClass) {
        return getPlugin(pluginClass, false);
    }

    public static <P extends ConstellioPlugin> P getDefaultPlugin(Class<P> pluginClass) {
        return getPlugin(pluginClass, true);
    }

    private static <P extends ConstellioPlugin> P getPlugin(Class<P> pluginClass, boolean onlyDefault) {
        List<P> matches = getPlugins(pluginClass, onlyDefault);
        return !matches.isEmpty() ? matches.get(0) : null;
    }

    public static <P extends ConstellioPlugin> List<P> getPlugins(Class<P> pluginClass) {
        return getPlugins(pluginClass, false);
    }

    public static <P extends ConstellioPlugin> List<P> getDefaultPlugins(Class<P> pluginClass) {
        return getPlugins(pluginClass, true);
    }

    private static <P extends ConstellioPlugin> List<P> getPlugins(Class<P> pluginClass, boolean onlyDefault) {
        List<P> matches = new ArrayList<P>();
        P defaultPlugin = null;

        initPluginManager();
        PluginManagerUtil pmu = new PluginManagerUtil(pm);
        for (P impl : pmu.getPlugins(pluginClass)) {
            // ClassLoader classLoader = impl.getClass().getClassLoader();
            // classLoaders.add(classLoader);
            if (DefaultConstellioPlugin.NAME.equals(impl.getName())) {
                defaultPlugin = impl;
            } else if (!onlyDefault) {
                matches.add(impl);
            }
        }
        if (matches.isEmpty()) {
            if (defaultPlugin != null) {
                matches.add(defaultPlugin);
            }
        } else {
            // If many plugins are found, they are sorted in the order they are configured in constellio.xml
            // (the last has priority over the previous)
            Collections.sort(matches, new Comparator<ConstellioPlugin>() {
                @Override
                public int compare(ConstellioPlugin o1, ConstellioPlugin o2) {
                    List<String> availablePluginNames = ConstellioSpringUtils.getAvailablePluginNames();
                    Integer indexOfPluginName1 = availablePluginNames.indexOf(o1.getName());
                    Integer indexOfPluginName2 = availablePluginNames.indexOf(o2.getName());
                    return indexOfPluginName1.compareTo(indexOfPluginName2);
                }
            });
        }
        return matches;
    }

    public static File getPluginsDir() {
        File webinfDir = ClasspathUtils.getWebinfDir();
        return new File(webinfDir, "plugins");
    }

    @SuppressWarnings("unchecked")
    public static boolean isValidPlugin(String name) {
        boolean validPlugin;
        File pluginsDir = getPluginsDir();
        File pluginDir = new File(pluginsDir, name);
        if (!pluginDir.exists() || pluginDir.isFile()) {
            validPlugin = false;
        } else {
            Collection<File> pluginJarFiles = FileUtils.listFiles(pluginDir, new String[] { "jar" }, false);
            // Accept only one root dir jar
            File pluginJarFile = pluginJarFiles.isEmpty() ? null : pluginJarFiles.iterator().next();
            if (pluginJarFile != null) {
                validPlugin = true;
            } else {
                validPlugin = false;
            }
        }
        return validPlugin;
    }

    public static Set<ClassLoader> getClassLoaders() {
        initPluginManager();
        return classLoaders;
    }

}

自定义类加载器PluginAwareClassLoader.java

/**
 * Constellio, Open Source Enterprise Search
 * Copyright (C) 2010 DocuLibre inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program 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 distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package com.doculibre.constellio.plugins;

import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Set;

public class PluginAwareClassLoader extends ClassLoader {
    
    private ClassLoader defaultClassLoader;
    
    public PluginAwareClassLoader() {
        defaultClassLoader = Thread.currentThread().getContextClassLoader();
        while (defaultClassLoader instanceof PluginAwareClassLoader) {
            PluginAwareClassLoader nested = (PluginAwareClassLoader) defaultClassLoader;
            defaultClassLoader = nested.getDefaultClassLoader();
        }
    }

    public ClassLoader getDefaultClassLoader() {
        return defaultClassLoader;
    }

    public void setDefaultClassLoader(ClassLoader defaultClassLoader) {
        this.defaultClassLoader = defaultClassLoader;
    }
    
    protected Set<ClassLoader> getExtraClassLoaders() {
        Set<ClassLoader> extraClassLoaders = PluginFactory.getClassLoaders();
        extraClassLoaders.add(PluginAwareClassLoader.class.getClassLoader());
        return extraClassLoaders;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> clazz;
        Throwable throwable;
        try {
            clazz = defaultClassLoader.loadClass(name);
            throwable = null;
        } catch (Throwable t) {
            clazz = null;
            throwable = t;
        }
        if (clazz == null) {
            for (ClassLoader extraClassLoader : getExtraClassLoaders()) {
                try {
                    clazz = extraClassLoader.loadClass(name);
                    if (clazz != null) {
                        break;
                    }
                } catch (ClassNotFoundException e) {
                    // Ignore, already handled
                }
            }
        }
        if (clazz == null && throwable != null) {
            if (throwable instanceof ClassNotFoundException) {
                throw (ClassNotFoundException) throwable;
            } else if (throwable instanceof RuntimeException) {
                throw (RuntimeException) throwable;
            } else {
                throw new RuntimeException(throwable);
            }
        } 
        return clazz;
    }

    @Override
    protected URL findResource(String name) {
        URL resource;
        Throwable throwable;
        try {
            resource = defaultClassLoader.getResource(name);
            throwable = null;
        } catch (Throwable t) {
            resource = null;
            throwable = t;
        }
        if (resource == null) {
            for (ClassLoader extraClassLoader : getExtraClassLoaders()) {
                resource = extraClassLoader.getResource(name);
                if (resource != null) {
                    break;
                }
            }
        }
        if (resource == null && throwable != null) {
            if (throwable instanceof RuntimeException) {
                throw (RuntimeException) throwable;
            } else {
                throw new RuntimeException(throwable);
            }
        } 
        return resource;
    }

    @Override
    protected Enumeration<URL> findResources(String name) throws IOException {
        Enumeration<URL> resources;
        Throwable throwable;
        try {
            resources = defaultClassLoader.getResources(name);
            throwable = null;
        } catch (Throwable t) {
            resources = null;
            throwable = t;
        }
        if (resources == null) {
            for (ClassLoader extraClassLoader : getExtraClassLoaders()) {
                resources = extraClassLoader.getResources(name);
                if (resources != null) {
                    break;
                }
            }
        }
        if (resources == null && throwable != null) {
            if (throwable instanceof IOException) {
                throw (IOException) throwable;
            } else if (throwable instanceof RuntimeException) {
                throw (RuntimeException) throwable;
            } else {
                throw new RuntimeException(throwable);
            }
        } 
        return resources;
    }

}

插件框架参考 http://www.cnblogs.com/chenying99/archive/2013/04/01/2994529.html

posted on 2013-02-17 22:30  刺猬的温驯  阅读(544)  评论(0编辑  收藏  举报