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