Move ClassLoaderUtils
[yangtools.git] / yang / yang-binding / src / main / java / org / opendaylight / yangtools / yang / binding / util / ClassLoaderUtils.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.binding.util;
9
10 import static com.google.common.base.Preconditions.checkNotNull;
11
12 import java.lang.reflect.Constructor;
13 import java.lang.reflect.InvocationTargetException;
14 import java.lang.reflect.ParameterizedType;
15 import java.lang.reflect.Type;
16 import java.util.Arrays;
17 import java.util.List;
18 import java.util.concurrent.Callable;
19 import java.util.concurrent.locks.Lock;
20
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 import com.google.common.base.Joiner;
25 import com.google.common.base.Preconditions;
26 import com.google.common.base.Supplier;
27
28 public final class ClassLoaderUtils {
29     private static final Logger LOG = LoggerFactory.getLogger(ClassLoaderUtils.class);
30
31     private ClassLoaderUtils() {
32         throw new UnsupportedOperationException("Utility class");
33     }
34
35     public static <V> V withClassLoader(final ClassLoader cls, final Supplier<V> function) {
36         checkNotNull(cls, "Classloader should not be null");
37         checkNotNull(function, "Function should not be null");
38
39         final ClassLoader oldCls = Thread.currentThread().getContextClassLoader();
40         try {
41             Thread.currentThread().setContextClassLoader(cls);
42             return function.get();
43         } finally {
44             Thread.currentThread().setContextClassLoader(oldCls);
45         }
46     }
47
48     public static <V> V withClassLoader(final ClassLoader cls, final Callable<V> function) throws Exception {
49         checkNotNull(cls, "Classloader should not be null");
50         checkNotNull(function, "Function should not be null");
51
52         final ClassLoader oldCls = Thread.currentThread().getContextClassLoader();
53         try {
54             Thread.currentThread().setContextClassLoader(cls);
55             return function.call();
56         } finally {
57             Thread.currentThread().setContextClassLoader(oldCls);
58         }
59     }
60
61     public static <V> V withClassLoaderAndLock(final ClassLoader cls, final Lock lock, final Supplier<V> function) {
62         checkNotNull(lock, "Lock should not be null");
63
64         lock.lock();
65         try {
66             return withClassLoader(cls, function);
67         } finally {
68             lock.unlock();
69         }
70     }
71
72     public static Object construct(final Constructor<? extends Object> constructor, final List<Object> objects)
73             throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
74         final Object[] initargs = objects.toArray();
75         return constructor.newInstance(initargs);
76     }
77
78     public static Class<?> loadClass(final ClassLoader cls, final String name) throws ClassNotFoundException {
79         if ("byte[]".equals(name)) {
80             return byte[].class;
81         }
82         if ("char[]".equals(name)) {
83             return char[].class;
84         }
85
86         try {
87             return cls.loadClass(name);
88         } catch (ClassNotFoundException e) {
89             String[] components = name.split("\\.");
90             String potentialOuter;
91             int length = components.length;
92             if (length > 2 && (potentialOuter = components[length - 2]) != null && Character.isUpperCase(potentialOuter.charAt(0))) {
93                     String outerName = Joiner.on(".").join(Arrays.asList(components).subList(0, length - 1));
94                     String innerName = outerName + "$" + components[length-1];
95                     return cls.loadClass(innerName);
96             } else {
97                 throw e;
98             }
99         }
100     }
101
102     public static Class<?> loadClassWithTCCL(final String name) throws ClassNotFoundException {
103         return loadClass(Thread.currentThread().getContextClassLoader(), name);
104     }
105
106     public static Class<?> tryToLoadClassWithTCCL(final String fullyQualifiedName) {
107         try {
108             return loadClassWithTCCL(fullyQualifiedName);
109         } catch (ClassNotFoundException e) {
110             LOG.debug("Failed to load class {}", fullyQualifiedName, e);
111             return null;
112         }
113     }
114
115     public static <S,G,P> Class<P> findFirstGenericArgument(final Class<S> scannedClass, final Class<G> genericType) {
116         return withClassLoader(scannedClass.getClassLoader(), ClassLoaderUtils.<S,G,P>findFirstGenericArgumentTask(scannedClass, genericType));
117     }
118
119     private static <S,G,P> Supplier<Class<P>> findFirstGenericArgumentTask(final Class<S> scannedClass, final Class<G> genericType) {
120         return new Supplier<Class<P>>() {
121             @Override
122             @SuppressWarnings("unchecked")
123             public Class<P> get() {
124                 final ParameterizedType augmentationGeneric = findParameterizedType(scannedClass, genericType);
125                 if (augmentationGeneric != null) {
126                     return (Class<P>) augmentationGeneric.getActualTypeArguments()[0];
127                 }
128                 return null;
129             }
130         };
131     }
132
133     public static ParameterizedType findParameterizedType(final Class<?> subclass, final Class<?> genericType) {
134         Preconditions.checkNotNull(subclass);
135         Preconditions.checkNotNull(genericType);
136
137         for (Type type : subclass.getGenericInterfaces()) {
138             if (type instanceof ParameterizedType && genericType.equals(((ParameterizedType) type).getRawType())) {
139                 return (ParameterizedType) type;
140             }
141         }
142
143         LOG.debug("Class {} does not declare interface {}", subclass, genericType);
144         return null;
145     }
146
147     public static Type getFirstGenericParameter(final Type type) {
148         if (type instanceof ParameterizedType) {
149             return ((ParameterizedType) type).getActualTypeArguments()[0];
150         }
151         return null;
152     }
153 }