bacff303f2ac28e5d6edddb6ed3abccb96a767d2
[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         synchronized (javAssist) {
77             javAssist.appendClassLoaderIfMissing(cls);
78             return ClassLoaderUtils.withClassLoader(cls, function);
79         }
80     }
81
82     protected final InstanceIdentifier<?> getBindingIdentifierByPath(final SchemaPath path) {
83         return PATH_TO_BINDING_IDENTIFIER.get(path);
84     }
85
86     protected final void putPathToBindingIdentifier(final SchemaPath path, final InstanceIdentifier<?> bindingIdentifier) {
87         PATH_TO_BINDING_IDENTIFIER.put(path, bindingIdentifier);
88     }
89
90     protected final InstanceIdentifier<?> putPathToBindingIdentifier(final SchemaPath path,
91             final InstanceIdentifier<?> bindingIdentifier, final Class<?> childClass) {
92         @SuppressWarnings({ "unchecked", "rawtypes" })
93         InstanceIdentifier<?> newId = bindingIdentifier.builder().child((Class) childClass).build();
94         PATH_TO_BINDING_IDENTIFIER.put(path, newId);
95         return newId;
96     }
97
98     protected abstract Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentationTransformerForImpl(Class<?> inputType);
99     protected abstract Class<? extends BindingCodec<Object, Object>> caseCodecForImpl(Class<?> inputType, ChoiceCaseNode node);
100     protected abstract Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifiableImpl(Class<?> parentType);
101     protected abstract Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifierImpl(Class<?> inputType);
102     protected abstract Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerForImpl(Class<?> inputType);
103
104     // Called from LazyGeneratedCodecRegistry
105     final Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentationTransformerFor(final Class<?> inputType) throws TransformerGeneratorException {
106         try {
107             return augmentationTransformerForImpl(inputType);
108         } catch (Exception e) {
109             throw TransformerGeneratorException.wrap(inputType, e);
110         }
111     }
112
113     final Class<? extends BindingCodec<Object, Object>> caseCodecFor(final Class<?> inputType, final ChoiceCaseNode node) throws TransformerGeneratorException {
114         try {
115             return caseCodecForImpl(inputType, node);
116         } catch (Exception e) {
117             throw TransformerGeneratorException.wrap(inputType, e);
118         }
119     }
120
121     final Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifiable(final Class<?> parentType) throws TransformerGeneratorException {
122         try {
123             return keyTransformerForIdentifiableImpl(parentType);
124         } catch (Exception e) {
125             throw TransformerGeneratorException.wrap(parentType, e);
126         }
127     }
128
129     final Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifier(final Class<?> inputType) throws TransformerGeneratorException {
130         try {
131             return keyTransformerForIdentifierImpl(inputType);
132         } catch (Exception e) {
133             throw TransformerGeneratorException.wrap(inputType, e);
134         }
135     }
136
137     final Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerFor(final Class<?> inputType) throws TransformerGeneratorException {
138         try {
139             return transformerForImpl(inputType);
140         } catch (Exception e) {
141             throw TransformerGeneratorException.wrap(inputType, e);
142         }
143     }
144 }