Modernize BindingStructuralType
[mdsal.git] / binding / mdsal-binding-dom-adapter / src / main / java / org / opendaylight / mdsal / binding / dom / adapter / BindingStructuralType.java
1 /*
2  * Copyright (c) 2015 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.mdsal.binding.dom.adapter;
9
10 import com.google.common.annotations.Beta;
11 import java.util.Optional;
12 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
13 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
14 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
15 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
16 import org.opendaylight.yangtools.yang.data.api.schema.AnyxmlNode;
17 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
18 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
19 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
20 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
28 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidateNode;
29
30 /**
31  * Defines structural mapping of Normalized Node to Binding data addressable by Instance Identifier. Not all binding
32  * data are addressable by instance identifier and there are some differences.
33  *
34  * <p>
35  * See {@link #NOT_ADDRESSABLE},{@link #INVISIBLE_CONTAINER},{@link #VISIBLE_CONTAINER} for more details.
36  *
37  * <p>
38  * NOTE: this class is exposed for migration purposes only, no new users outside of its package should be introduced.
39  */
40 @Beta
41 public enum BindingStructuralType {
42     /**
43      * DOM Item is not addressable in Binding InstanceIdentifier, data is not lost, but are available only via parent
44      * object. Such types of data are leaf-lists, leafs, list without keys or anyxml.
45      */
46     NOT_ADDRESSABLE,
47     /**
48      * Data container is addressable in NormalizedNode format, but in Binding it is not represented in
49      * InstanceIdentifier. These are choice / case nodes.
50      *
51      * <p>
52      * This data is still accessible using parent object and their children are addressable.
53      */
54     INVISIBLE_CONTAINER,
55     /**
56      * Data container is addressable in NormalizedNode format, but in Binding it is not represented in
57      * InstanceIdentifier. These are list nodes.
58      *
59      * <p>
60      * This data is still accessible using parent object and their children are addressable.
61      */
62     INVISIBLE_LIST,
63     /**
64      * Data container is addressable in Binding InstanceIdentifier format and also YangInstanceIdentifier format.
65      */
66     VISIBLE_CONTAINER,
67     /**
68      * Mapping algorithm was unable to detect type or was not updated after introduction of new NormalizedNode type.
69      */
70     UNKNOWN;
71
72     public static BindingStructuralType from(final DataTreeCandidateNode domChildNode) {
73         Optional<NormalizedNode> dataBased = domChildNode.getDataAfter();
74         if (!dataBased.isPresent()) {
75             dataBased = domChildNode.getDataBefore();
76         }
77         if (dataBased.isPresent()) {
78             return from(dataBased.get());
79         }
80         return from(domChildNode.getIdentifier());
81     }
82
83     private static BindingStructuralType from(final PathArgument identifier) {
84         if (identifier instanceof NodeIdentifierWithPredicates || identifier instanceof AugmentationIdentifier) {
85             return VISIBLE_CONTAINER;
86         }
87         if (identifier instanceof NodeWithValue) {
88             return NOT_ADDRESSABLE;
89         }
90         return UNKNOWN;
91     }
92
93     static BindingStructuralType from(final NormalizedNode data) {
94         if (isNotAddressable(data)) {
95             return NOT_ADDRESSABLE;
96         }
97         if (data instanceof MapNode) {
98             return INVISIBLE_LIST;
99         }
100         if (data instanceof ChoiceNode) {
101             return INVISIBLE_CONTAINER;
102         }
103         if (isVisibleContainer(data)) {
104             return VISIBLE_CONTAINER;
105         }
106         return UNKNOWN;
107     }
108
109     public static BindingStructuralType recursiveFrom(final DataTreeCandidateNode node) {
110         final BindingStructuralType type = BindingStructuralType.from(node);
111         return switch (type) {
112             case INVISIBLE_CONTAINER, INVISIBLE_LIST -> {
113                 // This node is invisible, try to resolve using a child node
114                 for (final DataTreeCandidateNode child : node.getChildNodes()) {
115                     final BindingStructuralType childType = recursiveFrom(child);
116                     yield switch (childType) {
117                             case INVISIBLE_CONTAINER, INVISIBLE_LIST ->
118                                 // Invisible nodes are not addressable
119                                 BindingStructuralType.NOT_ADDRESSABLE;
120                             case NOT_ADDRESSABLE, UNKNOWN, VISIBLE_CONTAINER -> childType;
121                         };
122                 }
123
124                 yield BindingStructuralType.NOT_ADDRESSABLE;
125             }
126             default -> type;
127         };
128     }
129
130     private static boolean isVisibleContainer(final NormalizedNode data) {
131         return data instanceof MapEntryNode || data instanceof ContainerNode || data instanceof AugmentationNode;
132     }
133
134     private static boolean isNotAddressable(final NormalizedNode normalizedNode) {
135         return normalizedNode instanceof LeafNode
136                 || normalizedNode instanceof AnyxmlNode
137                 || normalizedNode instanceof LeafSetNode
138                 || normalizedNode instanceof LeafSetEntryNode
139                 || normalizedNode instanceof UnkeyedListNode
140                 || normalizedNode instanceof UnkeyedListEntryNode;
141     }
142 }