BUG-983: convert sneakyThrow into checked exception
[yangtools.git] / code-generator / binding-generator-impl / src / main / java / org / opendaylight / yangtools / sal / binding / generator / util / JavassistUtils.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.sal.binding.generator.util;
9
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.Collection;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.WeakHashMap;
16 import java.util.concurrent.locks.Lock;
17 import java.util.concurrent.locks.ReentrantLock;
18
19 import javassist.CannotCompileException;
20 import javassist.ClassClassPath;
21 import javassist.ClassPath;
22 import javassist.ClassPool;
23 import javassist.CtClass;
24 import javassist.CtField;
25 import javassist.CtMethod;
26 import javassist.LoaderClassPath;
27 import javassist.Modifier;
28 import javassist.NotFoundException;
29
30 import org.eclipse.xtext.xbase.lib.Conversions;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import com.google.common.base.Preconditions;
35
36 public class JavassistUtils {
37     private static final Logger LOG = LoggerFactory.getLogger(JavassistUtils.class);
38
39     private final Map<ClassLoader, ClassPath> loaderClassPaths = new WeakHashMap<>();
40     private final Lock lock = new ReentrantLock();
41     private final ClassPool classPool;
42
43     public JavassistUtils(final ClassPool pool) {
44         classPool = Preconditions.checkNotNull(pool);
45     }
46
47     public Lock getLock() {
48         return lock;
49     }
50
51     public void method(final CtClass it, final Class<? extends Object> returnType, final String name,
52             final Class<? extends Object> parameter, final MethodGenerator function1) throws CannotCompileException {
53         List<CtClass> _asList = Arrays.<CtClass> asList(asCtClass(parameter));
54         CtMethod _ctMethod = new CtMethod(asCtClass(returnType), name, ((CtClass[]) Conversions.unwrapArray(
55                 _asList, CtClass.class)), it);
56
57         final CtMethod method = _ctMethod;
58         function1.process(method);
59         it.addMethod(method);
60     }
61
62     public void method(final CtClass it, final Class<? extends Object> returnType, final String name,
63             final Collection<? extends Class<?>> parameters, final MethodGenerator function1) throws CannotCompileException {
64         List<CtClass> _asList = new ArrayList<>();
65         for (Class<? extends Object> parameter : parameters) {
66             _asList.add(asCtClass(parameter));
67         }
68         CtMethod method = new CtMethod(asCtClass(returnType), name, ((CtClass[]) Conversions.unwrapArray(_asList,
69                 CtClass.class)), it);
70         function1.process(method);
71         it.addMethod(method);
72     }
73
74     public void staticMethod(final CtClass it, final Class<? extends Object> returnType, final String name,
75             final Class<? extends Object> parameter, final MethodGenerator function1) throws CannotCompileException {
76         List<CtClass> _asList = Arrays.<CtClass> asList(asCtClass(parameter));
77         CtMethod _ctMethod = new CtMethod(asCtClass(returnType), name, ((CtClass[]) Conversions.unwrapArray(
78                 _asList, CtClass.class)), it);
79         final CtMethod method = _ctMethod;
80         function1.process(method);
81         it.addMethod(method);
82     }
83
84     public void implementMethodsFrom(final CtClass target, final CtClass source, final MethodGenerator function1) throws CannotCompileException {
85         for (CtMethod method : source.getMethods()) {
86             if (method.getDeclaringClass() == source) {
87                 CtMethod redeclaredMethod = new CtMethod(method, target, null);
88                 function1.process(redeclaredMethod);
89                 target.addMethod(redeclaredMethod);
90             }
91         }
92     }
93
94     public CtClass createClass(final String fqn, final ClassGenerator cls) {
95         CtClass target = classPool.makeClass(fqn);
96         cls.process(target);
97         return target;
98     }
99
100     public CtClass createClass(final String fqn, final CtClass superInterface, final ClassGenerator cls) {
101         CtClass target = classPool.makeClass(fqn);
102         implementsType(target, superInterface);
103         cls.process(target);
104         return target;
105     }
106
107     public void implementsType(final CtClass it, final CtClass supertype) {
108         Preconditions.checkArgument(supertype.isInterface(), "Supertype must be interface");
109         it.addInterface(supertype);
110     }
111
112     public CtClass asCtClass(final Class<? extends Object> class1) {
113         return get(this.classPool, class1);
114     }
115
116     public CtField field(final CtClass it, final String name, final Class<? extends Object> returnValue) throws CannotCompileException {
117         final CtField field = new CtField(asCtClass(returnValue), name, it);
118         field.setModifiers(Modifier.PUBLIC);
119         it.addField(field);
120         return field;
121     }
122
123     public CtField staticField(final CtClass it, final String name, final Class<? extends Object> returnValue) throws CannotCompileException {
124         final CtField field = new CtField(asCtClass(returnValue), name, it);
125         field.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
126         it.addField(field);
127         return field;
128     }
129
130     public CtClass get(final ClassPool pool, final Class<? extends Object> cls) {
131         try {
132             return pool.get(cls.getName());
133         } catch (NotFoundException nfe1) {
134             appendClassLoaderIfMissing(cls.getClassLoader());
135             try {
136                 return pool.get(cls.getName());
137             } catch (final NotFoundException nfe2) {
138                 LOG.warn("Appending ClassClassPath for {}", cls, nfe2);
139                 pool.appendClassPath(new ClassClassPath(cls));
140                 try {
141                     return pool.get(cls.getName());
142                 } catch (NotFoundException e) {
143                     LOG.warn("Failed to load class {} from pool {}", cls, pool, e);
144                     throw new IllegalStateException("Failed to load class", e);
145                 }
146             }
147         }
148     }
149
150     public synchronized void appendClassLoaderIfMissing(final ClassLoader loader) {
151         // FIXME: this works as long as the ClassPool is not shared between instances of this class
152         //        How is synchronization across multiple instances done? The ClassPool itself just
153         //        keeps on adding the loaders and does not check for duplicates!
154         if (!loaderClassPaths.containsKey(loader)) {
155             final ClassPath ctLoader = new LoaderClassPath(loader);
156             classPool.appendClassPath(ctLoader);
157             loaderClassPaths.put(loader, ctLoader);
158         }
159     }
160
161     public void ensureClassLoader(final Class<?> child) {
162         appendClassLoaderIfMissing(child.getClassLoader());
163     }
164 }