Adopt odlparent-10.0.0/yangtools-8.0.0-SNAPSHOT
[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         switch (type) {
112             case INVISIBLE_CONTAINER:
113             case INVISIBLE_LIST:
114                 // This node is invisible, try to resolve using a child node
115                 for (final DataTreeCandidateNode child : node.getChildNodes()) {
116                     final BindingStructuralType childType = recursiveFrom(child);
117                     switch (childType) {
118                         case INVISIBLE_CONTAINER:
119                         case INVISIBLE_LIST:
120                             // Invisible nodes are not addressable
121                             return BindingStructuralType.NOT_ADDRESSABLE;
122                         case NOT_ADDRESSABLE:
123                         case UNKNOWN:
124                         case VISIBLE_CONTAINER:
125                             return childType;
126                         default:
127                             throw new IllegalStateException("Unhandled child type " + childType + " for child "
128                                     + child);
129                     }
130                 }
131
132                 return BindingStructuralType.NOT_ADDRESSABLE;
133             default:
134                 return type;
135         }
136     }
137
138     private static boolean isVisibleContainer(final NormalizedNode data) {
139         return data instanceof MapEntryNode || data instanceof ContainerNode || data instanceof AugmentationNode;
140     }
141
142     private static boolean isNotAddressable(final NormalizedNode normalizedNode) {
143         return normalizedNode instanceof LeafNode
144                 || normalizedNode instanceof AnyxmlNode
145                 || normalizedNode instanceof LeafSetNode
146                 || normalizedNode instanceof LeafSetEntryNode
147                 || normalizedNode instanceof UnkeyedListNode
148                 || normalizedNode instanceof UnkeyedListEntryNode;
149     }
150 }