9ecf70678ea98b035e920e11f37cbe7ba895ed8d
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / CodecDataObjectAnalysis.java
1 /*
2  * Copyright (c) 2023 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.impl;
9
10 import com.google.common.base.VerifyException;
11 import java.lang.invoke.MethodHandle;
12 import java.lang.invoke.MethodHandles;
13 import java.lang.invoke.MethodType;
14 import java.lang.reflect.Method;
15 import java.util.List;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
18 import org.opendaylight.mdsal.binding.runtime.api.AugmentableRuntimeType;
19 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
20 import org.opendaylight.yangtools.yang.binding.Augmentable;
21 import org.opendaylight.yangtools.yang.binding.DataObject;
22 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
23
24 /**
25  * Analysis of a {@link DataObject} specialization class. The primary point of this class is to separate out creation
26  * indices needed for {@link #proxyConstructor}. Since we want to perform as much indexing as possible in a single pass,
27  * we also end up indexing things that are not strictly required to arrive at that constructor.
28  */
29 final class CodecDataObjectAnalysis<R extends CompositeRuntimeType> extends AbstractDataContainerAnalysis<R> {
30     private static final MethodType CONSTRUCTOR_TYPE = MethodType.methodType(void.class,
31         AbstractDataObjectCodecContext.class, DataContainerNode.class);
32     private static final MethodType DATAOBJECT_TYPE = MethodType.methodType(DataObject.class,
33         AbstractDataObjectCodecContext.class, DataContainerNode.class);
34
35     final @NonNull Class<? extends CodecDataObject<?>> generatedClass;
36     final @NonNull List<AugmentRuntimeType> possibleAugmentations;
37     final @NonNull MethodHandle proxyConstructor;
38
39     CodecDataObjectAnalysis(final CommonDataObjectCodecPrototype<R> prototype, final CodecItemFactory itemFactory,
40             final Method keyMethod) {
41         this(prototype.getBindingClass(), prototype.getType(), prototype.getFactory(), itemFactory, keyMethod);
42     }
43
44     CodecDataObjectAnalysis(final Class<?> bindingClass, final R runtimeType, final CodecContextFactory factory,
45             final CodecItemFactory itemFactory, final Method keyMethod) {
46         super(bindingClass, runtimeType, factory, itemFactory);
47
48         // Final bits: generate the appropriate class, As a side effect we identify what Augmentations are possible
49         if (Augmentable.class.isAssignableFrom(bindingClass)) {
50             // Verify we have the appropriate backing runtimeType
51             if (!(runtimeType instanceof AugmentableRuntimeType augmentableRuntimeType)) {
52                 throw new VerifyException(
53                     "Unexpected type %s backing augmenable %s".formatted(runtimeType, bindingClass));
54             }
55
56             possibleAugmentations = augmentableRuntimeType.augments();
57             generatedClass = CodecDataObjectGenerator.generateAugmentable(factory.getLoader(), bindingClass,
58                 leafContexts, daoProperties, keyMethod);
59         } else {
60             possibleAugmentations = List.of();
61             generatedClass = CodecDataObjectGenerator.generate(factory.getLoader(), bindingClass, leafContexts,
62                 daoProperties, keyMethod);
63         }
64
65         // All done: acquire the constructor: it is supposed to be public
66         final MethodHandle ctor;
67         try {
68             ctor = MethodHandles.publicLookup().findConstructor(generatedClass, CONSTRUCTOR_TYPE);
69         } catch (NoSuchMethodException | IllegalAccessException e) {
70             throw new LinkageError("Failed to find contructor for class " + generatedClass, e);
71         }
72
73         proxyConstructor = ctor.asType(DATAOBJECT_TYPE);
74     }
75 }