Migrate users of Builders/ImmutableNodes
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / AbstractDataObjectCodecContext.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.collect.ImmutableMap;
11 import com.google.common.collect.ImmutableSet;
12 import java.util.List;
13 import java.util.Map;
14 import org.eclipse.jdt.annotation.NonNull;
15 import org.eclipse.jdt.annotation.Nullable;
16 import org.opendaylight.mdsal.binding.dom.codec.api.IncorrectNestingException;
17 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
18 import org.opendaylight.yangtools.yang.binding.Augmentation;
19 import org.opendaylight.yangtools.yang.binding.DataObject;
20 import org.opendaylight.yangtools.yang.binding.DataObjectStep;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
23 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
24 import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
25
26 /**
27  * Abstract base for {@link DataObjectCodecContext} and {@link AugmentationCodecContext}. They share most of their
28  * mechanics, but notably:
29  * <ol>
30  *   <li>DataObjectCodecContext has an exact DistinctNodeContainer and YangInstanceIdentifier mapping and can be the
31  *       target of augmentations (i.e. can implement Augmentable contract)</li>
32  *   <li>AugmentationNodeContext has neither of those traits and really is just a filter of its parent
33  *       DistinctNodeContainer</li>
34  * </ol>
35  *
36  * <p>
37  * Unfortunately {@code Augmentation} is a also a {@link DataObject}, so things get a bit messy.
38  *
39  * <p>
40  * While this class is public, it not part of API surface and is an implementation detail. The only reason for it being
41  * public is that it needs to be accessible by code generated at runtime.
42  */
43 public abstract sealed class AbstractDataObjectCodecContext<D extends DataObject, T extends CompositeRuntimeType>
44         extends CommonDataObjectCodecContext<D, T>
45         permits AugmentationCodecContext, DataObjectCodecContext {
46     private final ImmutableMap<Class<?>, DataContainerPrototype<?, ?>> byBindingArgClass;
47     private final ImmutableMap<Class<?>, DataContainerPrototype<?, ?>> byStreamClass;
48     private final ImmutableMap<NodeIdentifier, CodecContextSupplier> byYang;
49     private final ImmutableMap<String, ValueNodeCodecContext> leafChild;
50
51     AbstractDataObjectCodecContext(final CommonDataObjectCodecPrototype<T> prototype,
52             final DataContainerAnalysis<T> analysis) {
53         super(prototype);
54         byBindingArgClass = analysis.byBindingArgClass;
55         byStreamClass = analysis.byStreamClass;
56         byYang = analysis.byYang;
57         leafChild = analysis.leafNodes;
58     }
59
60     @Override
61     @Deprecated(since = "13.0.0", forRemoval = true)
62     public final WithStatus getSchema() {
63         // FIXME: Bad cast, we should be returning an EffectiveStatement perhaps?
64         return (WithStatus) prototype().runtimeType().statement();
65     }
66
67     @Override
68     DataContainerPrototype<?, ?> streamChildPrototype(final Class<?> childClass) {
69         return byStreamClass.get(childClass);
70     }
71
72     @Override
73     public final CommonDataObjectCodecContext<?, ?> bindingPathArgumentChild(final DataObjectStep<?> step,
74             final List<PathArgument> builder) {
75         final var type = step.type();
76         final var context = childNonNull(pathChildPrototype(type), type,
77             "Class %s is not valid child of %s", type, getBindingClass())
78             .getCodecContext();
79         context.addYangPathArgument(step, builder);
80         if (context instanceof CommonDataObjectCodecContext<?, ?> dataObject) {
81             return dataObject;
82         } else if (context instanceof ChoiceCodecContext<?> choice) {
83             return choice.bindingPathArgumentChild(step, builder);
84         } else {
85             throw new IllegalStateException("Unhandled context " + context);
86         }
87     }
88
89     @Nullable DataContainerPrototype<?, ?> pathChildPrototype(final @NonNull Class<? extends DataObject> argType) {
90         return byBindingArgClass.get(argType);
91     }
92
93     @Override
94     CodecContextSupplier yangChildSupplier(final NodeIdentifier arg) {
95         return byYang.get(arg);
96     }
97
98     final ValueNodeCodecContext getLeafChild(final String name) {
99         final ValueNodeCodecContext value = leafChild.get(name);
100         if (value == null) {
101             throw new IncorrectNestingException("Leaf %s is not valid for %s", name, getBindingClass());
102         }
103         return value;
104     }
105
106     final @NonNull ImmutableSet<NodeIdentifier> byYangKeySet() {
107         return byYang.keySet();
108     }
109
110     abstract @NonNull Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAllAugmentationsFrom(
111         DataContainerNode data);
112 }