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