mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-25 11:45:49 +01:00
safe caller: respect classloader of the class and the interfaces (#763)
Related to: https://github.com/openhab/openhab2-addons/issues/5519 Signed-off-by: Markus Rathgeb <maggu2810@gmail.com>
This commit is contained in:
parent
1ac2e8978b
commit
25d7f14dfc
@ -0,0 +1,117 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2019 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.smarthome.core.internal.common;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Combines multiple class loaders into one.
|
||||
*
|
||||
* @author Markus Rathgeb - Initial contribution
|
||||
*
|
||||
*/
|
||||
public class CombinedClassLoader extends ClassLoader {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(CombinedClassLoader.class);
|
||||
private final Map<ClassLoader, Set<Class<?>>> delegateClassLoaders;
|
||||
|
||||
private static String info(final ClassLoader classLoader, final Set<Class<?>> clazzes) {
|
||||
return String.format("classloader \"%s\" for \"%s\"", classLoader, clazzes);
|
||||
}
|
||||
|
||||
public static CombinedClassLoader fromClasses(final ClassLoader parent, final Stream<Class<?>> delegateClasses) {
|
||||
final Map<ClassLoader, Set<Class<?>>> cls = new HashMap<>();
|
||||
delegateClasses.forEach(clazz -> {
|
||||
cls.compute(clazz.getClassLoader(), (k, v) -> {
|
||||
if (v == null) {
|
||||
final Set<Class<?>> set = new HashSet<>();
|
||||
set.add(clazz);
|
||||
return set;
|
||||
} else {
|
||||
v.add(clazz);
|
||||
return v;
|
||||
}
|
||||
});
|
||||
});
|
||||
return new CombinedClassLoader(parent, cls);
|
||||
}
|
||||
|
||||
public static CombinedClassLoader fromClassLoaders(final ClassLoader parent,
|
||||
final ClassLoader... delegateClassLoaders) {
|
||||
return fromClassLoaders(parent, Arrays.stream(delegateClassLoaders));
|
||||
}
|
||||
|
||||
public static CombinedClassLoader fromClassLoaders(final ClassLoader parent,
|
||||
final Stream<ClassLoader> delegateClassLoaders) {
|
||||
return new CombinedClassLoader(parent,
|
||||
delegateClassLoaders.collect(Collectors.toMap(cl -> cl, cl -> Collections.emptySet())));
|
||||
}
|
||||
|
||||
private CombinedClassLoader(ClassLoader parent, Map<ClassLoader, Set<Class<?>>> delegateClassLoaders) {
|
||||
super(parent);
|
||||
this.delegateClassLoaders = Collections.unmodifiableMap(delegateClassLoaders);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
for (final Entry<ClassLoader, Set<Class<?>>> entry : delegateClassLoaders.entrySet()) {
|
||||
try {
|
||||
final Class<?> clazz = entry.getKey().loadClass(name);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Loaded class \"{}\" by {}", name, info(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
return clazz;
|
||||
} catch (final ClassNotFoundException ex) {
|
||||
}
|
||||
}
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URL findResource(String name) {
|
||||
// Try to get the resource from one of the delegate class loaders.
|
||||
// Return the first found one.
|
||||
// If no delegate class loader can get the resource, return null.
|
||||
return delegateClassLoaders.keySet().stream().map(cl -> cl.getResource(name)).filter(Objects::nonNull)
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Enumeration<URL> findResources(String name) throws IOException {
|
||||
final Vector<URL> vector = new Vector<>();
|
||||
for (final ClassLoader delegate : delegateClassLoaders.keySet()) {
|
||||
final Enumeration<URL> enumeration = delegate.getResources(name);
|
||||
while (enumeration.hasMoreElements()) {
|
||||
vector.add(enumeration.nextElement());
|
||||
}
|
||||
}
|
||||
return vector.elements();
|
||||
}
|
||||
|
||||
}
|
@ -16,7 +16,9 @@ import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
@ -65,7 +67,10 @@ public class SafeCallerBuilderImpl<T> implements SafeCallerBuilder<T> {
|
||||
handler = new InvocationHandlerSync<T>(manager, target, identifier, timeout, exceptionHandler,
|
||||
timeoutHandler);
|
||||
}
|
||||
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), interfaceTypes, handler);
|
||||
return (T) Proxy.newProxyInstance(
|
||||
CombinedClassLoader.fromClasses(getClass().getClassLoader(),
|
||||
Stream.concat(Stream.of(target.getClass()), Arrays.stream(interfaceTypes))),
|
||||
interfaceTypes, handler);
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user