Introduce NormalizedNode.Builder interfaces
[yangtools.git] / data / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / schema / ImmutableNodes.java
1 /*
2  * Copyright (c) 2014 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.yangtools.yang.data.impl.schema;
9
10 import java.io.IOException;
11 import org.eclipse.jdt.annotation.NonNull;
12 import org.opendaylight.yangtools.yang.common.QName;
13 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
14 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
15 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
16 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
17 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
18 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
19 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
20 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.UserMapNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.stream.YangInstanceIdentifierWriter;
26 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
27 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
28 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
29
30 public final class ImmutableNodes {
31     // FIXME: YANGTOOLS-1074: we do not want this name
32     private static final NodeIdentifier SCHEMACONTEXT_NAME = NodeIdentifier.create(SchemaContext.NAME);
33
34     private ImmutableNodes() {
35         // Hidden on purpose
36     }
37
38     public static SystemMapNode.@NonNull Builder mapNodeBuilder() {
39         return Builders.mapBuilder();
40     }
41
42     public static SystemMapNode.@NonNull Builder mapNodeBuilder(final QName name) {
43         return mapNodeBuilder(NodeIdentifier.create(name));
44     }
45
46     public static SystemMapNode.@NonNull Builder mapNodeBuilder(final NodeIdentifier name) {
47         final var ret = Builders.mapBuilder();
48         // FIXME: use fluent once we have specialized enough
49         ret.withNodeIdentifier(name);
50         return ret;
51     }
52
53     /**
54      * Create an immutable map node.
55      *
56      * @param name QName which will be used as node identifier
57      * @return An unordered Map node
58      */
59     public static @NonNull SystemMapNode mapNode(final QName name) {
60         return mapNode(NodeIdentifier.create(name));
61     }
62
63     /**
64      * Create an immutable map node.
65      *
66      * @param name QName which will be used as node identifier
67      * @return An unordered Map node
68      */
69     public static @NonNull SystemMapNode mapNode(final NodeIdentifier name) {
70         return mapNodeBuilder(name).build();
71     }
72
73     /**
74      * Create immutable ordered map node.
75      *
76      * @param name QName which will be used as node identifier
77      * @return An ordered Map node
78      */
79     public static @NonNull UserMapNode orderedMapNode(final QName name) {
80         return orderedMapNode(NodeIdentifier.create(name));
81     }
82
83     /**
84      * Create immutable ordered map node.
85      *
86      * @param name Node identifier
87      * @return An ordered Map node
88      */
89     public static @NonNull UserMapNode orderedMapNode(final NodeIdentifier name) {
90         return Builders.orderedMapBuilder().withNodeIdentifier(name).build();
91     }
92
93     /**
94      * Construct immutable leaf node.
95      *
96      * @param name Identifier of leaf node
97      * @param value Value of leaf node
98      * @param <T> Type of leaf node value
99      * @return Leaf node with supplied identifier and value
100      */
101     public static <T> @NonNull LeafNode<T> leafNode(final NodeIdentifier name, final T value) {
102         return ImmutableLeafNodeBuilder.createNode(name, value);
103     }
104
105     /**
106      * Construct immutable leaf node.
107      *
108      * @param name QName which will be used as node identifier
109      * @param value Value of leaf node.
110      * @param <T> Type of leaf node value
111      * @return Leaf node with supplied identifier and value
112      */
113     public static <T> @NonNull LeafNode<T> leafNode(final QName name, final T value) {
114         return leafNode(NodeIdentifier.create(name), value);
115     }
116
117     public static MapEntryNode.@NonNull Builder mapEntryBuilder(final QName nodeName, final QName keyName,
118             final Object keyValue) {
119         final var ret = Builders.mapEntryBuilder();
120         // FIXME: use fluent once we have specialized enough
121         ret.withNodeIdentifier(NodeIdentifierWithPredicates.of(nodeName, keyName, keyValue))
122             .withChild(leafNode(keyName, keyValue));
123         return ret;
124
125     }
126
127     public static MapEntryNode.@NonNull Builder mapEntryBuilder() {
128         return Builders.mapEntryBuilder();
129     }
130
131     public static @NonNull MapEntryNode mapEntry(final QName nodeName, final QName keyName, final Object keyValue) {
132         return mapEntryBuilder(nodeName, keyName, keyValue).build();
133     }
134
135     /**
136      * Create an immutable container node.
137      *
138      * @param name QName which will be used as node identifier
139      * @return A container node
140      */
141     public static @NonNull ContainerNode containerNode(final QName name) {
142         return containerNode(NodeIdentifier.create(name));
143     }
144
145     /**
146      * Create an immutable container node.
147      *
148      * @param name Node identifier
149      * @return A container node
150      */
151     public static @NonNull ContainerNode containerNode(final NodeIdentifier name) {
152         return Builders.containerBuilder().withNodeIdentifier(name).build();
153     }
154
155     /**
156      * Create an immutable choice node.
157      *
158      * @param name QName which will be used as node identifier
159      * @return A choice node
160      */
161     public static @NonNull ChoiceNode choiceNode(final QName name) {
162         return choiceNode(NodeIdentifier.create(name));
163     }
164
165     /**
166      * Create an immutable choice node.
167      *
168      * @param name Node identifier
169      * @return A choice node
170      */
171     public static @NonNull ChoiceNode choiceNode(final NodeIdentifier name) {
172         return Builders.choiceBuilder().withNodeIdentifier(name).build();
173     }
174
175     /**
176      * Create an immutable list node.
177      *
178      * @param name QName which will be used as node identifier
179      * @return An unkeyed list node
180      */
181     public static @NonNull UnkeyedListNode listNode(final QName name) {
182         return listNode(NodeIdentifier.create(name));
183     }
184
185     /**
186      * Create an immutable list node.
187      *
188      * @param name Node identifier
189      * @return An unkeyed list node
190      */
191     public static @NonNull UnkeyedListNode listNode(final NodeIdentifier name) {
192         return Builders.unkeyedListBuilder().withNodeIdentifier(name).build();
193     }
194
195     /**
196      * Convert YangInstanceIdentifier into a normalized node structure.
197      *
198      * @param ctx schema context to used during serialization
199      * @param id instance identifier to convert to node structure starting from root
200      * @return serialized normalized node for provided instance Id
201      * @throws NullPointerException if any argument is null
202      * @throws IllegalArgumentException if the identifier cannot be converted
203      */
204     public static @NonNull NormalizedNode fromInstanceId(final EffectiveModelContext ctx,
205             final YangInstanceIdentifier id) {
206         if (id.isEmpty()) {
207             return containerNode(SCHEMACONTEXT_NAME);
208         }
209
210         final var result = new NormalizationResultHolder();
211         try (var writer = ImmutableNormalizedNodeStreamWriter.from(result)) {
212             try (var iidWriter = YangInstanceIdentifierWriter.open(writer, ctx, id)) {
213                 // leaf-list entry nodes are special: they require a value and we can derive it from our instance
214                 // identitifier
215                 final var lastArg = id.getLastPathArgument();
216                 if (lastArg instanceof NodeWithValue<?> withValue) {
217                     writer.scalarValue(withValue.getValue());
218                 }
219             }
220         } catch (IOException e) {
221             throw new IllegalArgumentException("Failed to convert " + id, e);
222         }
223         return result.getResult().data();
224     }
225 }