Merge "BUG-1381: guide users to use external synchronized block"
[yangtools.git] / code-generator / binding-generator-impl / src / main / java / org / opendaylight / yangtools / sal / binding / generator / impl / AbstractTransformerGenerator.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.impl;
9
10 import com.google.common.base.Preconditions;
11
12 import java.util.Map;
13 import java.util.concurrent.Callable;
14 import java.util.concurrent.ConcurrentHashMap;
15 import java.util.concurrent.locks.Lock;
16
17 import javassist.ClassPool;
18
19 import org.eclipse.xtext.xbase.lib.Extension;
20 import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
21 import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
22 import org.opendaylight.yangtools.yang.binding.BindingCodec;
23 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
24 import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
27 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
28
29 /**
30  * Abstract base class which defines the baseline for the real {@link TransformerGenerator}.
31  * This class exists to expose the basic interface and common interactions with the rest
32  * of the package.
33  */
34 abstract class AbstractTransformerGenerator {
35     private static final Map<SchemaPath, InstanceIdentifier<?>> PATH_TO_BINDING_IDENTIFIER = new ConcurrentHashMap<>();
36
37     /*
38      * The generator has to always use this strategy, otherwise we may end up
39      * will VerificationErrors.
40      */
41     @Extension
42     protected static final ClassLoadingStrategy CLASS_LOADING_STRATEGY = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
43     @Extension
44     protected final TypeResolver typeResolver;
45     @Extension
46     protected final JavassistUtils javAssist;
47
48     /*
49      * This is effectively final, but we have an implementation circle, where this
50      * class notifies LazyGeneratedCodecRegistry and it calls our methods. The
51      * listener is initialized to non-null before it is exposed.
52      */
53     private GeneratorListener listener;
54
55     protected AbstractTransformerGenerator(final TypeResolver typeResolver, final ClassPool pool) {
56         this.typeResolver = Preconditions.checkNotNull(typeResolver);
57         this.javAssist = JavassistUtils.forClassPool(pool);
58     }
59
60     protected final GeneratorListener getListener() {
61         if (listener == null) {
62             synchronized (this) {
63                 Preconditions.checkState(listener != null, "Implementation not fully initialized");
64             }
65         }
66
67         return listener;
68     }
69
70     synchronized final void setListener(final GeneratorListener listener) {
71         Preconditions.checkState(this.listener == null, "Implementation already initialized");
72         this.listener = Preconditions.checkNotNull(listener);
73     }
74
75     protected final <V> V runOnClassLoader(final ClassLoader cls, final Callable<V> function) throws Exception {
76         final Lock lock = javAssist.getLock();
77
78         lock.lock();
79         try {
80             synchronized (javAssist) {
81                 javAssist.appendClassLoaderIfMissing(cls);
82                 return ClassLoaderUtils.withClassLoader(cls, function);
83             }
84         } finally {
85             lock.unlock();
86         }
87     }
88
89     protected final InstanceIdentifier<?> getBindingIdentifierByPath(final SchemaPath path) {
90         return PATH_TO_BINDING_IDENTIFIER.get(path);
91     }
92
93     protected final void putPathToBindingIdentifier(final SchemaPath path, final InstanceIdentifier<?> bindingIdentifier) {
94         PATH_TO_BINDING_IDENTIFIER.put(path, bindingIdentifier);
95     }
96
97     protected final InstanceIdentifier<?> putPathToBindingIdentifier(final SchemaPath path,
98             final InstanceIdentifier<?> bindingIdentifier, final Class<?> childClass) {
99         @SuppressWarnings({ "unchecked", "rawtypes" })
100         InstanceIdentifier<?> newId = bindingIdentifier.builder().child((Class) childClass).build();
101         PATH_TO_BINDING_IDENTIFIER.put(path, newId);
102         return newId;
103     }
104
105     protected abstract Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentationTransformerForImpl(Class<?> inputType);
106     protected abstract Class<? extends BindingCodec<Object, Object>> caseCodecForImpl(Class<?> inputType, ChoiceCaseNode node);
107     protected abstract Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifiableImpl(Class<?> parentType);
108     protected abstract Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifierImpl(Class<?> inputType);
109     protected abstract Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerForImpl(Class<?> inputType);
110
111     // Called from LazyGeneratedCodecRegistry
112     final Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentationTransformerFor(final Class<?> inputType) throws TransformerGeneratorException {
113         try {
114             return augmentationTransformerForImpl(inputType);
115         } catch (Exception e) {
116             throw TransformerGeneratorException.wrap(inputType, e);
117         }
118     }
119
120     final Class<? extends BindingCodec<Object, Object>> caseCodecFor(final Class<?> inputType, final ChoiceCaseNode node) throws TransformerGeneratorException {
121         try {
122             return caseCodecForImpl(inputType, node);
123         } catch (Exception e) {
124             throw TransformerGeneratorException.wrap(inputType, e);
125         }
126     }
127
128     final Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifiable(final Class<?> parentType) throws TransformerGeneratorException {
129         try {
130             return keyTransformerForIdentifiableImpl(parentType);
131         } catch (Exception e) {
132             throw TransformerGeneratorException.wrap(parentType, e);
133         }
134     }
135
136     final Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifier(final Class<?> inputType) throws TransformerGeneratorException {
137         try {
138             return keyTransformerForIdentifierImpl(inputType);
139         } catch (Exception e) {
140             throw TransformerGeneratorException.wrap(inputType, e);
141         }
142     }
143
144     final Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerFor(final Class<?> inputType) throws TransformerGeneratorException {
145         try {
146             return transformerForImpl(inputType);
147         } catch (Exception e) {
148             throw TransformerGeneratorException.wrap(inputType, e);
149         }
150     }
151 }