a2b7ac6fe0efcdfa3696feae941abf7c5ca25637
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / loader / StaticClassPool.java
1 /*
2  * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.mdsal.binding.dom.codec.loader;
9
10 import static com.google.common.base.Verify.verify;
11 import static com.google.common.base.Verify.verifyNotNull;
12
13 import com.google.common.annotations.Beta;
14 import java.security.AccessController;
15 import java.security.PrivilegedAction;
16 import javassist.ClassPool;
17 import javassist.CtClass;
18 import javassist.LoaderClassPath;
19 import javassist.NotFoundException;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.yangtools.yang.binding.DataContainer;
22
23 /**
24  * Static class pool, bound to the class loader of binding-dom-codec. It can be used to acquire CtClass instances that
25  * reside within the binding-dom-codec artifact or any of its direct mandatory dependencies. It can also instantiate
26  * {@link CodecClassLoader} instances for use with code generation.
27  *
28  * @author Robert Varga
29  */
30 @Beta
31 public final class StaticClassPool {
32     static final ClassLoader LOADER = verifyNotNull(StaticClassPool.class.getClassLoader());
33     static final ClassPool POOL;
34
35     static {
36         final ClassPool pool = new ClassPool();
37         pool.appendClassPath(new LoaderClassPath(LOADER));
38         POOL = pool;
39     }
40
41     private StaticClassPool() {
42         // Utility class
43     }
44
45     /**
46      * Instantiate a new CodecClassLoader.
47      *
48      * @return A new CodecClassLoader.
49      */
50     public static @NonNull CodecClassLoader createLoader() {
51         return AccessController.doPrivileged((PrivilegedAction<CodecClassLoader>)() -> new RootCodecClassLoader());
52     }
53
54     /**
55      * Resolve a binding-dom-codec class to its {@link CtClass} counterpart.
56      *
57      * @param clazz Class to resolve
58      * @return A CtClass instance
59      * @throws IllegalStateException if the class cannot be resolved
60      * @throws NullPointerException if {@code clazz} is null
61      */
62     public static synchronized @NonNull CtClass findClass(final @NonNull Class<?> clazz) {
63         final CtClass ret;
64         try {
65             ret = POOL.get(clazz.getName());
66         } catch (NotFoundException e) {
67             throw new IllegalStateException("Failed to find " + clazz, e);
68         }
69         ret.freeze();
70         return ret;
71     }
72
73     // Sanity check: target has to resolve yang-binding contents to the same class, otherwise we are in a pickle
74     static void verifyStaticLinkage(final ClassLoader candidate) {
75         final Class<?> targetClazz;
76         try {
77             targetClazz = candidate.loadClass(DataContainer.class.getName());
78         } catch (ClassNotFoundException e) {
79             throw new IllegalStateException("ClassLoader " + candidate + " cannot load " + DataContainer.class, e);
80         }
81         verify(DataContainer.class.equals(targetClazz),
82             "Class mismatch on DataContainer. Ours is from %s, target %s has %s from %s",
83             DataContainer.class.getClassLoader(), candidate, targetClazz, targetClazz.getClassLoader());
84     }
85 }