Merge "Bug 735 - Part 1: Update ietf-restconf and ietf-yangtypes to newer versions"
[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     /**
36      *
37      * Runs {@link Supplier} with provided {@link ClassLoader}.
38      *
39      * Invokes supplies function and makes sure that original {@link ClassLoader}
40      * is context {@link ClassLoader} after execution.
41      *
42      * @param cls {@link ClassLoader} to be used.
43      * @param function Function to be executed.
44      * @return Result of supplier invocation.
45      *
46      */
47     public static <V> V withClassLoader(final ClassLoader cls, final Supplier<V> function) {
48         checkNotNull(cls, "Classloader should not be null");
49         checkNotNull(function, "Function should not be null");
50
51         final ClassLoader oldCls = Thread.currentThread().getContextClassLoader();
52         try {
53             Thread.currentThread().setContextClassLoader(cls);
54             return function.get();
55         } finally {
56             Thread.currentThread().setContextClassLoader(oldCls);
57         }
58     }
59
60     /**
61     *
62     * Runs {@link Callable} with provided {@link ClassLoader}.
63     *
64     * Invokes supplies function and makes sure that original {@link ClassLoader}
65     * is context {@link ClassLoader} after execution.
66     *
67     * @param cls {@link ClassLoader} to be used.
68     * @param function Function to be executed.
69     * @return Result of callable invocation.
70     *
71     */
72     public static <V> V withClassLoader(final ClassLoader cls, final Callable<V> function) throws Exception {
73         checkNotNull(cls, "Classloader should not be null");
74         checkNotNull(function, "Function should not be null");
75
76         final ClassLoader oldCls = Thread.currentThread().getContextClassLoader();
77         try {
78             Thread.currentThread().setContextClassLoader(cls);
79             return function.call();
80         } finally {
81             Thread.currentThread().setContextClassLoader(oldCls);
82         }
83     }
84
85    /**
86     *
87     * Runs {@link Callable} with provided {@link ClassLoader} and Lock.
88     *
89     * Invokes supplies function after acquiring lock
90     * and makes sure that original {@link ClassLoader}
91     * is context {@link ClassLoader} and lock is unlocked
92     * after execution.
93     *
94     * @param cls {@link ClassLoader} to be used.
95     * @param function Function to be executed.
96     * @return Result of Callable invocation.
97     *
98     */
99     public static <V> V withClassLoaderAndLock(final ClassLoader cls, final Lock lock, final Supplier<V> function) {
100         checkNotNull(lock, "Lock should not be null");
101
102         lock.lock();
103         try {
104             return withClassLoader(cls, function);
105         } finally {
106             lock.unlock();
107         }
108     }
109
110     public static Object construct(final Constructor<? extends Object> constructor, final List<Object> objects)
111             throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
112         final Object[] initargs = objects.toArray();
113         return constructor.newInstance(initargs);
114     }
115
116     /**
117      *
118      * Loads class using this supplied classloader.
119      *
120      *
121      * @param cls
122      * @param name String name of class.
123      * @return
124      * @throws ClassNotFoundException
125      */
126     public static Class<?> loadClass(final ClassLoader cls, final String name) throws ClassNotFoundException {
127         if ("byte[]".equals(name)) {
128             return byte[].class;
129         }
130         if ("char[]".equals(name)) {
131             return char[].class;
132         }
133
134         try {
135             return cls.loadClass(name);
136         } catch (ClassNotFoundException e) {
137             String[] components = name.split("\\.");
138             String potentialOuter;
139             int length = components.length;
140             if (length > 2 && (potentialOuter = components[length - 2]) != null && Character.isUpperCase(potentialOuter.charAt(0))) {
141                     String outerName = Joiner.on(".").join(Arrays.asList(components).subList(0, length - 1));
142                     String innerName = outerName + "$" + components[length-1];
143                     return cls.loadClass(innerName);
144             } else {
145                 throw e;
146             }
147         }
148     }
149
150     public static Class<?> loadClassWithTCCL(final String name) throws ClassNotFoundException {
151         return loadClass(Thread.currentThread().getContextClassLoader(), name);
152     }
153
154     public static Class<?> tryToLoadClassWithTCCL(final String fullyQualifiedName) {
155         try {
156             return loadClassWithTCCL(fullyQualifiedName);
157         } catch (ClassNotFoundException e) {
158             LOG.debug("Failed to load class {}", fullyQualifiedName, e);
159             return null;
160         }
161     }
162
163     public static <S,G,P> Class<P> findFirstGenericArgument(final Class<S> scannedClass, final Class<G> genericType) {
164         return withClassLoader(scannedClass.getClassLoader(), ClassLoaderUtils.<S,G,P>findFirstGenericArgumentTask(scannedClass, genericType));
165     }
166
167     private static <S,G,P> Supplier<Class<P>> findFirstGenericArgumentTask(final Class<S> scannedClass, final Class<G> genericType) {
168         return new Supplier<Class<P>>() {
169             @Override
170             @SuppressWarnings("unchecked")
171             public Class<P> get() {
172                 final ParameterizedType augmentationGeneric = findParameterizedType(scannedClass, genericType);
173                 if (augmentationGeneric != null) {
174                     return (Class<P>) augmentationGeneric.getActualTypeArguments()[0];
175                 }
176                 return null;
177             }
178         };
179     }
180
181     public static ParameterizedType findParameterizedType(final Class<?> subclass, final Class<?> genericType) {
182         Preconditions.checkNotNull(subclass);
183         Preconditions.checkNotNull(genericType);
184
185         for (Type type : subclass.getGenericInterfaces()) {
186             if (type instanceof ParameterizedType && genericType.equals(((ParameterizedType) type).getRawType())) {
187                 return (ParameterizedType) type;
188             }
189         }
190
191         LOG.debug("Class {} does not declare interface {}", subclass, genericType);
192         return null;
193     }
194
195     public static Type getFirstGenericParameter(final Type type) {
196         if (type instanceof ParameterizedType) {
197             return ((ParameterizedType) type).getActualTypeArguments()[0];
198         }
199         return null;
200     }
201 }