/**
* 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 classLoaders = new HashSet();
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 availablePluginNames = ConstellioSpringUtils.getAvailablePluginNames();
accept = availablePluginNames.contains(pathname.getName());
}
return accept;
}
});
for (File pluginDir : pluginDirs) {
// Plugin root dir jars
Collection 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 pluginDependencies = FileUtils.listFiles(pluginLibDir,
new String[] { "jar" }, false);
ClassPathManagerUtils.addJarDependencies(classPathManager, pluginJarFile,
pluginDependencies);
}
}
}
}
}
public static P getPlugin(Class pluginClass) {
return getPlugin(pluginClass, false);
}
public static P getDefaultPlugin(Class pluginClass) {
return getPlugin(pluginClass, true);
}
private static P getPlugin(Class pluginClass, boolean onlyDefault) {
List matches = getPlugins(pluginClass, onlyDefault);
return !matches.isEmpty() ? matches.get(0) : null;
}
public static List getPlugins(Class pluginClass) {
return getPlugins(pluginClass, false);
}
public static List getDefaultPlugins(Class pluginClass) {
return getPlugins(pluginClass, true);
}
private static List getPlugins(Class pluginClass, boolean onlyDefault) {
List matches = new ArrayList();
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() {
@Override
public int compare(ConstellioPlugin o1, ConstellioPlugin o2) {
List 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 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 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 getExtraClassLoaders() {
Set 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 findResources(String name) throws IOException {
Enumeration 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.iyunv.com/chenying99/archive/2013/04/01/2994529.html