From ea042f82433b98d89f26843453caffc44d5c7388 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Sun, 18 May 2014 15:07:58 +0200 Subject: [PATCH] Move ClassLoaderUtils This patch makes an attempt at unifying and improving the two ClassLoaderUtils versions we have available. This is a prerequisite to being able to being able to maintain them properly. At this point the sanest place for them is yang-binding, as it has guava, slf4j and is at least transitively pulled from all users. Change-Id: Iea7ae5fb7ef40f9af960ca01b000f81237c70ab0 Signed-off-by: Robert Varga --- .../impl/AbstractTransformerGenerator.java | 2 +- .../impl/GeneratedClassLoadingStrategy.java | 12 +- .../impl/ModuleInfoBackedContext.java | 45 +++--- .../generator/util/ClassLoaderUtils.java | 4 + .../concepts/util/ClassLoaderUtils.java | 15 +- .../yang/binding/util/BindingReflections.java | 6 +- .../yang/binding/util/ClassLoaderUtils.java | 153 ++++++++++++++++++ 7 files changed, 197 insertions(+), 40 deletions(-) create mode 100644 yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/ClassLoaderUtils.java diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/AbstractTransformerGenerator.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/AbstractTransformerGenerator.java index fd280427d4..373ea7df71 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/AbstractTransformerGenerator.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/AbstractTransformerGenerator.java @@ -16,10 +16,10 @@ import javassist.ClassPool; import org.eclipse.xtext.xbase.lib.Extension; import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy; -import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils; import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; import org.opendaylight.yangtools.yang.binding.BindingCodec; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; import org.opendaylight.yangtools.yang.model.api.SchemaPath; diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratedClassLoadingStrategy.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratedClassLoadingStrategy.java index 362ebe6e88..5440e01511 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratedClassLoadingStrategy.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/GeneratedClassLoadingStrategy.java @@ -8,25 +8,26 @@ package org.opendaylight.yangtools.sal.binding.generator.impl; import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy; -import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils; import org.opendaylight.yangtools.sal.binding.model.api.Type; +import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils; public abstract class GeneratedClassLoadingStrategy implements ClassLoadingStrategy { private static final GeneratedClassLoadingStrategy TCCL_STRATEGY = new TCCLClassLoadingStrategy(); private static final GeneratedClassLoadingStrategy ALWAYS_FAIL_STRATEGY = new GeneratedClassLoadingStrategy() { - @Override - public Class loadClass(String fullyQualifiedName) throws ClassNotFoundException { + public Class loadClass(final String fullyQualifiedName) throws ClassNotFoundException { throw new ClassNotFoundException(fullyQualifiedName); } }; - public Class loadClass(Type type) throws ClassNotFoundException { + @Override + public Class loadClass(final Type type) throws ClassNotFoundException { return loadClass(type.getFullyQualifiedName()); } + @Override public abstract Class loadClass(String fullyQualifiedName) throws ClassNotFoundException; public static final GeneratedClassLoadingStrategy getTCCLClassLoadingStrategy() { @@ -38,9 +39,8 @@ public abstract class GeneratedClassLoadingStrategy implements ClassLoadingStrat } private static final class TCCLClassLoadingStrategy extends GeneratedClassLoadingStrategy { - @Override - public Class loadClass(String fullyQualifiedName) throws ClassNotFoundException { + public Class loadClass(final String fullyQualifiedName) throws ClassNotFoundException { return ClassLoaderUtils.loadClassWithTCCL(fullyQualifiedName); } } diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/ModuleInfoBackedContext.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/ModuleInfoBackedContext.java index cf5c83d729..335ec5967e 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/ModuleInfoBackedContext.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/ModuleInfoBackedContext.java @@ -7,16 +7,20 @@ */ package org.opendaylight.yangtools.sal.binding.generator.impl; -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.WeakReference; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; import org.opendaylight.yangtools.concepts.ObjectRegistration; import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy; import org.opendaylight.yangtools.sal.binding.generator.api.ModuleInfoRegistry; -import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils; import org.opendaylight.yangtools.yang.binding.YangModuleInfo; import org.opendaylight.yangtools.yang.binding.util.BindingReflections; +import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider; @@ -26,18 +30,15 @@ import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.io.InputStream; -import java.lang.ref.WeakReference; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy // implements // AdvancedSchemaSourceProvider, ModuleInfoRegistry, SchemaContextProvider { - private ModuleInfoBackedContext(ClassLoadingStrategy loadingStrategy) { + private ModuleInfoBackedContext(final ClassLoadingStrategy loadingStrategy) { this.backingLoadingStrategy = loadingStrategy; } @@ -45,7 +46,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy // return new ModuleInfoBackedContext(getTCCLClassLoadingStrategy()); } - public static ModuleInfoBackedContext create(ClassLoadingStrategy loadingStrategy) { + public static ModuleInfoBackedContext create(final ClassLoadingStrategy loadingStrategy) { return new ModuleInfoBackedContext(loadingStrategy); } @@ -57,7 +58,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy // private final ClassLoadingStrategy backingLoadingStrategy; @Override - public Class loadClass(String fullyQualifiedName) throws ClassNotFoundException { + public Class loadClass(final String fullyQualifiedName) throws ClassNotFoundException { String modulePackageName = BindingReflections.getModelRootPackageName(fullyQualifiedName); WeakReference classLoaderRef = packageNameToClassLoader.get(modulePackageName); @@ -110,7 +111,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy // return sourceStreams.build(); } - private boolean resolveModuleInfo(Class cls) { + private boolean resolveModuleInfo(final Class cls) { try { return resolveModuleInfo(BindingReflections.getModuleInfo(cls)); } catch (Exception e) { @@ -118,7 +119,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy // } } - private boolean resolveModuleInfo(YangModuleInfo moduleInfo) { + private boolean resolveModuleInfo(final YangModuleInfo moduleInfo) { SourceIdentifier identifier = sourceIdentifierFrom(moduleInfo); YangModuleInfo previous = sourceIdentifierToModuleInfo.putIfAbsent(identifier, moduleInfo); @@ -136,18 +137,18 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy // return true; } - private SourceIdentifier sourceIdentifierFrom(YangModuleInfo moduleInfo) { + private SourceIdentifier sourceIdentifierFrom(final YangModuleInfo moduleInfo) { return SourceIdentifier.create(moduleInfo.getName(), Optional.of(moduleInfo.getRevision())); } - public void addModuleInfos(Iterable moduleInfos) { + public void addModuleInfos(final Iterable moduleInfos) { for (YangModuleInfo yangModuleInfo : moduleInfos) { registerModuleInfo(yangModuleInfo); } } @Override - public ObjectRegistration registerModuleInfo(YangModuleInfo yangModuleInfo) { + public ObjectRegistration registerModuleInfo(final YangModuleInfo yangModuleInfo) { YangModuleInfoRegistration registration = new YangModuleInfoRegistration(yangModuleInfo, this); resolveModuleInfo(yangModuleInfo); @@ -156,7 +157,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy // } @Override - public Optional getSchemaSource(SourceIdentifier sourceIdentifier) { + public Optional getSchemaSource(final SourceIdentifier sourceIdentifier) { YangModuleInfo info = sourceIdentifierToModuleInfo.get(sourceIdentifier); if (info == null) { return Optional.absent(); @@ -169,7 +170,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy // } @Override - public Optional getSchemaSource(String moduleName, Optional revision) { + public Optional getSchemaSource(final String moduleName, final Optional revision) { return getSchemaSource(SourceIdentifier.create(moduleName, revision)); } @@ -177,7 +178,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy // private final ModuleInfoBackedContext context; - public YangModuleInfoRegistration(YangModuleInfo instance, ModuleInfoBackedContext context) { + public YangModuleInfoRegistration(final YangModuleInfo instance, final ModuleInfoBackedContext context) { super(instance); this.context = context; } @@ -189,7 +190,7 @@ public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy // } - private void remove(YangModuleInfoRegistration registration) { + private void remove(final YangModuleInfoRegistration registration) { // FIXME implement } diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java index 1589552893..01ed2f0240 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/ClassLoaderUtils.java @@ -19,6 +19,10 @@ import java.util.concurrent.locks.Lock; import com.google.common.base.Joiner; import com.google.common.base.Optional; +/** + * @deprecated Use {@link org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils} instead. + */ +@Deprecated public final class ClassLoaderUtils { private ClassLoaderUtils() { diff --git a/common/concepts/src/main/java/org/opendaylight/yangtools/concepts/util/ClassLoaderUtils.java b/common/concepts/src/main/java/org/opendaylight/yangtools/concepts/util/ClassLoaderUtils.java index f2402270ef..e898e72479 100644 --- a/common/concepts/src/main/java/org/opendaylight/yangtools/concepts/util/ClassLoaderUtils.java +++ b/common/concepts/src/main/java/org/opendaylight/yangtools/concepts/util/ClassLoaderUtils.java @@ -12,18 +12,21 @@ import java.lang.reflect.Type; import java.util.concurrent.Callable; import java.util.concurrent.locks.Lock; - +/** + * @deprecated Use {@link org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils} instead. + */ +@Deprecated public final class ClassLoaderUtils { private ClassLoaderUtils() { throw new UnsupportedOperationException("Utility class"); } - public static V withClassLoader(ClassLoader cls, Callable function) throws Exception { + public static V withClassLoader(final ClassLoader cls, final Callable function) throws Exception { return withClassLoaderAndLock(cls, null, function); } - public static V withClassLoaderAndLock(ClassLoader cls, Lock lock, Callable function) throws Exception { + public static V withClassLoaderAndLock(final ClassLoader cls, final Lock lock, final Callable function) throws Exception { if (cls == null) { throw new IllegalArgumentException("Classloader should not be null"); } @@ -46,7 +49,7 @@ public final class ClassLoaderUtils { } } - public static ParameterizedType findParameterizedType(Class subclass, Class genericType) { + public static ParameterizedType findParameterizedType(final Class subclass, final Class genericType) { if(subclass == null || genericType == null) { throw new IllegalArgumentException("Class was not specified."); } @@ -65,7 +68,7 @@ public final class ClassLoaderUtils { return null; } } - + private static Callable> findFirstGenericArgumentTask(final Class scannedClass, final Class genericType) { return new Callable>() { @Override @@ -81,7 +84,7 @@ public final class ClassLoaderUtils { }; } - public static Type getFirstGenericParameter(Type type) { + public static Type getFirstGenericParameter(final Type type) { if(type instanceof ParameterizedType) { return ((ParameterizedType) type).getActualTypeArguments()[0]; } diff --git a/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java index 5e1494c55e..b0671397f3 100644 --- a/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java +++ b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/BindingReflections.java @@ -9,7 +9,6 @@ package org.opendaylight.yangtools.yang.binding.util; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; -import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.withClassLoader; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -22,7 +21,6 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils; import org.opendaylight.yangtools.yang.binding.Augmentable; import org.opendaylight.yangtools.yang.binding.Augmentation; import org.opendaylight.yangtools.yang.binding.BaseIdentity; @@ -35,7 +33,6 @@ import org.opendaylight.yangtools.yang.binding.RpcService; import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider; import org.opendaylight.yangtools.yang.binding.YangModuleInfo; import org.opendaylight.yangtools.yang.common.QName; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -202,8 +199,7 @@ public class BindingReflections { checkArgument(cls != null); String packageName = getModelRootPackageName(cls.getPackage()); final String potentialClassName = getModuleInfoClassName(packageName); - return withClassLoader(cls.getClassLoader(), new Callable() { - + return ClassLoaderUtils.withClassLoader(cls.getClassLoader(), new Callable() { @Override public YangModuleInfo call() throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { Class moduleInfoClass = Thread.currentThread().getContextClassLoader().loadClass(potentialClassName); diff --git a/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/ClassLoaderUtils.java b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/ClassLoaderUtils.java new file mode 100644 index 0000000000..e61aa73dcc --- /dev/null +++ b/yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/util/ClassLoaderUtils.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.yang.binding.util; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.locks.Lock; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; +import com.google.common.base.Supplier; + +public final class ClassLoaderUtils { + private static final Logger LOG = LoggerFactory.getLogger(ClassLoaderUtils.class); + + private ClassLoaderUtils() { + throw new UnsupportedOperationException("Utility class"); + } + + public static V withClassLoader(final ClassLoader cls, final Supplier function) { + checkNotNull(cls, "Classloader should not be null"); + checkNotNull(function, "Function should not be null"); + + final ClassLoader oldCls = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(cls); + return function.get(); + } finally { + Thread.currentThread().setContextClassLoader(oldCls); + } + } + + public static V withClassLoader(final ClassLoader cls, final Callable function) throws Exception { + checkNotNull(cls, "Classloader should not be null"); + checkNotNull(function, "Function should not be null"); + + final ClassLoader oldCls = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(cls); + return function.call(); + } finally { + Thread.currentThread().setContextClassLoader(oldCls); + } + } + + public static V withClassLoaderAndLock(final ClassLoader cls, final Lock lock, final Supplier function) { + checkNotNull(lock, "Lock should not be null"); + + lock.lock(); + try { + return withClassLoader(cls, function); + } finally { + lock.unlock(); + } + } + + public static Object construct(final Constructor constructor, final List objects) + throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + final Object[] initargs = objects.toArray(); + return constructor.newInstance(initargs); + } + + public static Class loadClass(final ClassLoader cls, final String name) throws ClassNotFoundException { + if ("byte[]".equals(name)) { + return byte[].class; + } + if ("char[]".equals(name)) { + return char[].class; + } + + try { + return cls.loadClass(name); + } catch (ClassNotFoundException e) { + String[] components = name.split("\\."); + String potentialOuter; + int length = components.length; + if (length > 2 && (potentialOuter = components[length - 2]) != null && Character.isUpperCase(potentialOuter.charAt(0))) { + String outerName = Joiner.on(".").join(Arrays.asList(components).subList(0, length - 1)); + String innerName = outerName + "$" + components[length-1]; + return cls.loadClass(innerName); + } else { + throw e; + } + } + } + + public static Class loadClassWithTCCL(final String name) throws ClassNotFoundException { + return loadClass(Thread.currentThread().getContextClassLoader(), name); + } + + public static Class tryToLoadClassWithTCCL(final String fullyQualifiedName) { + try { + return loadClassWithTCCL(fullyQualifiedName); + } catch (ClassNotFoundException e) { + LOG.debug("Failed to load class {}", fullyQualifiedName, e); + return null; + } + } + + public static Class

findFirstGenericArgument(final Class scannedClass, final Class genericType) { + return withClassLoader(scannedClass.getClassLoader(), ClassLoaderUtils.findFirstGenericArgumentTask(scannedClass, genericType)); + } + + private static Supplier> findFirstGenericArgumentTask(final Class scannedClass, final Class genericType) { + return new Supplier>() { + @Override + @SuppressWarnings("unchecked") + public Class

get() { + final ParameterizedType augmentationGeneric = findParameterizedType(scannedClass, genericType); + if (augmentationGeneric != null) { + return (Class

) augmentationGeneric.getActualTypeArguments()[0]; + } + return null; + } + }; + } + + public static ParameterizedType findParameterizedType(final Class subclass, final Class genericType) { + Preconditions.checkNotNull(subclass); + Preconditions.checkNotNull(genericType); + + for (Type type : subclass.getGenericInterfaces()) { + if (type instanceof ParameterizedType && genericType.equals(((ParameterizedType) type).getRawType())) { + return (ParameterizedType) type; + } + } + + LOG.debug("Class {} does not declare interface {}", subclass, genericType); + return null; + } + + public static Type getFirstGenericParameter(final Type type) { + if (type instanceof ParameterizedType) { + return ((ParameterizedType) type).getActualTypeArguments()[0]; + } + return null; + } +} -- 2.36.6