@@ -21,6 +21,7 @@ import java.util.Set; | |||
import org.apache.commons.lang.StringUtils; | |||
import ro.fortsoft.pf4j.DefaultPluginManager; | |||
import ro.fortsoft.pf4j.JarPluginManager; | |||
import ro.fortsoft.pf4j.PluginManager; | |||
import ro.fortsoft.pf4j.PluginWrapper; | |||
import ro.fortsoft.pf4j.demo.api.Greeting; | |||
@@ -37,7 +38,8 @@ public class Boot { | |||
printLogo(); | |||
// create the plugin manager | |||
final PluginManager pluginManager = new DefaultPluginManager(); | |||
// final PluginManager pluginManager = new DefaultPluginManager(); | |||
final PluginManager pluginManager = new JarPluginManager(); | |||
// load the plugins | |||
pluginManager.loadPlugins(); |
@@ -5,7 +5,7 @@ log4j.rootLogger=DEBUG, Console | |||
# | |||
log4j.logger.ro.fortsoft.pf4j=DEBUG, Console | |||
# !!! Put the bellow classes on level TRACE when you are in trouble | |||
log4j.logger.ro.fortsoft.pf4j.PluginClassLoader=WARN, Console | |||
log4j.logger.ro.fortsoft.pf4j.PluginClassLoader=DEBUG, Console | |||
log4j.logger.ro.fortsoft.pf4j.AbstractExtensionFinder=DEBUG, Console | |||
log4j.additivity.ro.fortsoft.pf4j=false | |||
log4j.additivity.ro.fortsoft.pf4j.PluginClassLoader=false |
@@ -17,6 +17,7 @@ package ro.fortsoft.pf4j; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import ro.fortsoft.pf4j.util.ClassUtils; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
@@ -106,6 +107,9 @@ public abstract class AbstractExtensionFinder implements ExtensionFinder, Plugin | |||
log.debug("Added extension '{}' with ordinal {}", className, extensionWrapper.getOrdinal()); | |||
} else { | |||
log.trace("'{}' is not an extension for extension point '{}'", className, type.getName()); | |||
if (RuntimeMode.DEVELOPMENT.equals(pluginManager.getRuntimeMode())) { | |||
checkDifferentClassLoaders(type, extensionClass); | |||
} | |||
} | |||
} catch (ClassNotFoundException e) { | |||
log.error(e.getMessage(), e); | |||
@@ -229,4 +233,15 @@ public abstract class AbstractExtensionFinder implements ExtensionFinder, Plugin | |||
return extensionWrapper; | |||
} | |||
private void checkDifferentClassLoaders(Class<?> type, Class<?> extensionClass) { | |||
ClassLoader typeClassLoader = type.getClassLoader(); // class loader of extension point | |||
ClassLoader extensionClassLoader = extensionClass.getClassLoader(); | |||
boolean match = ClassUtils.getAllInterfacesNames(extensionClass).contains(type.getSimpleName()); | |||
if (match && !extensionClassLoader.equals(typeClassLoader)) { | |||
// in this scenario the method 'isAssignableFrom' returns only FALSE | |||
// see http://www.coderanch.com/t/557846/java/java/FWIW-FYI-isAssignableFrom-isInstance-differing | |||
log.error("Different class loaders: '{}' (E) and '{}' (EP)", extensionClassLoader, typeClassLoader); | |||
} | |||
} | |||
} |
@@ -0,0 +1,91 @@ | |||
/* | |||
* Copyright 2016 Decebal Suiu | |||
* | |||
* Licensed 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 ro.fortsoft.pf4j.util; | |||
import java.lang.reflect.Modifier; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* @author Decebal Suiu | |||
*/ | |||
public class ClassUtils { | |||
public static List<String> getAllInterfacesNames(Class<?> aClass) { | |||
return toString(getAllInterfaces(aClass)); | |||
} | |||
public static List<Class<?>> getAllInterfaces(Class<?> aClass) { | |||
List<Class<?>> list = new ArrayList<>(); | |||
while (aClass != null) { | |||
Class<?>[] interfaces = aClass.getInterfaces(); | |||
for (Class<?> anInterface : interfaces) { | |||
if (!list.contains(anInterface)) { | |||
list.add(anInterface); | |||
} | |||
List<Class<?>> superInterfaces = getAllInterfaces(anInterface); | |||
for (Class<?> superInterface : superInterfaces) { | |||
if (!list.contains(superInterface)) { | |||
list.add(superInterface); | |||
} | |||
} | |||
} | |||
aClass = aClass.getSuperclass(); | |||
} | |||
return list; | |||
} | |||
/* | |||
public static List<String> getAllAbstractClassesNames(Class<?> aClass) { | |||
return toString(getAllInterfaces(aClass)); | |||
} | |||
public static List getAllAbstractClasses(Class aClass) { | |||
List<Class<?>> list = new ArrayList<>(); | |||
Class<?> superclass = aClass.getSuperclass(); | |||
while (superclass != null) { | |||
if (Modifier.isAbstract(superclass.getModifiers())) { | |||
list.add(superclass); | |||
} | |||
superclass = superclass.getSuperclass(); | |||
} | |||
return list; | |||
} | |||
*/ | |||
/** | |||
* Uses {@link Class#getSimpleName()} to convert from {@link Class} to {@link String}. | |||
* | |||
* @param classes | |||
* @return | |||
*/ | |||
private static List<String> toString(List<Class<?>> classes) { | |||
List<String> list = new ArrayList<>(); | |||
for (Class<?> aClass : classes) { | |||
list.add(aClass.getSimpleName()); | |||
} | |||
return list; | |||
} | |||
} |