Reparent ChoiceCodecContext
[mdsal.git] / binding / mdsal-binding-dom-codec-api / src / main / java / org / opendaylight / mdsal / binding / dom / codec / api / BindingDataObjectCodecTreeParent.java
1 /*
2  * Copyright (c) 2022 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.api;
9
10 import com.google.common.annotations.Beta;
11 import org.eclipse.jdt.annotation.NonNull;
12 import org.opendaylight.yangtools.yang.binding.Augmentation;
13 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
14 import org.opendaylight.yangtools.yang.binding.DataObject;
15
16 /**
17  * Common interface for entities which can supply a {@link BindingDataObjectCodecTreeNode} based on Binding DataObject
18  * class instance.
19  *
20  * @param <T> Dummy parameter to work around problems with streaming {@link ChoiceIn} classes. Essentially we want
21  *            {@link #getStreamChild(Class)} to also service such classes, which are not {@link DataObject}s. The
22  *            problem really is that {@code case} interfaces are DataObjects and hence are an alluring target for that
23  *            method. The workaround works with two sides:
24  *            <ul>
25  *              <li>Here the fact that we are generic means that binary compatibility dictates that our signature be
26  *                  backwards compatible with anyone who might have seen us as non-generic, i.e. in streamChild() taking
27  *                  a raw class (because there were no generics)</li>
28  *              <li>Users pick it up from there: all they need to do is to go to raw types, then accepts any class, but
29  *                  from there we can just chain on method return, arriving into a type-safe world again</li>
30  *            </ul>
31  */
32 @Beta
33 // FIXME: Now the above documentation is fine and dandy, but can we adjust the shape of our classes somehow?
34 //        The problem seems to be grouping interfaces, which are pulling in 'DataObject' to the picture and thus
35 //        and up marking case statements even if we do not mark them specially. If we could disconnect concrete cases
36 //        from DataObject in a civil manner, then we could go the DataObject -> ChoiceIn -> CaseOf and not have
37 //        choice/case statements in the picture. But what would that do to all the concepts hanging off of DataObject?
38 public interface BindingDataObjectCodecTreeParent<T> {
39     /**
40      * Returns child context as if it was walked by {@link BindingStreamEventWriter}. This means that to enter case,
41      * one must issue {@code getStreamChild(ChoiceClass).getStreamChild(CaseClass)}.
42      *
43      * @param <E> Stream child DataObject type
44      * @param childClass Child class by Binding Stream navigation
45      * @return Context of child
46      * @throws NullPointerException if {@code childClass} is {@code null}
47      * @throws IllegalArgumentException If supplied child class is not valid in specified context.
48      */
49     <E extends DataObject> @NonNull BindingDataContainerCodecTreeNode<E> getStreamChild(@NonNull Class<E> childClass);
50
51     default <A extends Augmentation<?>> @NonNull BindingAugmentationCodecTreeNode<A> getStreamAugmentation(
52             final @NonNull Class<A> childClass) {
53         final var result = getStreamChild(childClass);
54         if (result instanceof BindingAugmentationCodecTreeNode) {
55             return (BindingAugmentationCodecTreeNode<A>) result;
56         }
57         throw new IllegalArgumentException("Child " + childClass.getName() + " results in non-Augmentation " + result);
58     }
59
60     default <E extends DataObject> @NonNull BindingDataObjectCodecTreeNode<E> getStreamDataObject(
61             final @NonNull Class<E> childClass) {
62         final var result = getStreamChild(childClass);
63         if (result instanceof BindingDataObjectCodecTreeNode) {
64             return (BindingDataObjectCodecTreeNode<E>) result;
65         }
66         throw new IllegalArgumentException("Child " + childClass.getName() + " results in non-DataObject " + result);
67     }
68 }