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