Make MinMaxElementsValidation type-safe
[yangtools.git] / yang / 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 static com.google.common.base.Preconditions.checkNotNull;
11
12 import java.util.Iterator;
13 import java.util.Map.Entry;
14 import java.util.Optional;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
22 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
30 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
31 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
32 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder;
33 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
34 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
35 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
36 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
37 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder;
38 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListNodeBuilder;
39 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
41
42 public final class ImmutableNodes {
43     private static final NodeIdentifier SCHEMACONTEXT_NAME = NodeIdentifier.create(SchemaContext.NAME);
44
45     private ImmutableNodes() {
46         throw new UnsupportedOperationException("Utilities class should not be instantiated");
47     }
48
49     public static @NonNull CollectionNodeBuilder<MapEntryNode, MapNode> mapNodeBuilder() {
50         return ImmutableMapNodeBuilder.create();
51     }
52
53     public static @NonNull CollectionNodeBuilder<MapEntryNode, MapNode> mapNodeBuilder(final QName name) {
54         return mapNodeBuilder(NodeIdentifier.create(name));
55     }
56
57     public static @NonNull CollectionNodeBuilder<MapEntryNode, MapNode> mapNodeBuilder(final NodeIdentifier name) {
58         return ImmutableMapNodeBuilder.create().withNodeIdentifier(name);
59     }
60
61     /**
62      * Create an immutable map node.
63      *
64      * @param name QName which will be used as node identifier
65      * @return An unordered Map node
66      */
67     public static @NonNull MapNode mapNode(final QName name) {
68         return mapNodeBuilder(name).build();
69     }
70
71     private static @NonNull CollectionNodeBuilder<MapEntryNode, OrderedMapNode> orderedMapNodeBuilder(
72             final QName qname) {
73         return orderedMapNodeBuilder().withNodeIdentifier(NodeIdentifier.create(qname));
74     }
75
76     private static @NonNull CollectionNodeBuilder<MapEntryNode, OrderedMapNode> orderedMapNodeBuilder() {
77         return ImmutableOrderedMapNodeBuilder.create();
78     }
79
80     /**
81      * Create immutable ordered map node.
82      *
83      * @param name QName which will be used as node identifier
84      * @return An ordered Map node
85      */
86     public static @NonNull OrderedMapNode orderedMapNode(final QName name) {
87         return orderedMapNodeBuilder(name).build();
88     }
89
90     /**
91      * Construct immutable leaf node.
92      *
93      * @param name Identifier of leaf node
94      * @param value Value of leaf node
95      * @param <T> Type of leaf node value
96      * @return Leaf node with supplied identifier and value
97      */
98     public static <T> @NonNull LeafNode<T> leafNode(final NodeIdentifier name, final T value) {
99         return ImmutableLeafNodeBuilder.<T>create()
100                 .withNodeIdentifier(name)
101                 .withValue(value)
102                 .build();
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 @NonNull DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder(
118             final QName nodeName, final QName keyName, final Object keyValue) {
119         return ImmutableMapEntryNodeBuilder.create()
120                 .withNodeIdentifier(new NodeIdentifierWithPredicates(nodeName, keyName, keyValue))
121                 .withChild(leafNode(keyName, keyValue));
122     }
123
124     public static @NonNull DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder() {
125         return ImmutableMapEntryNodeBuilder.create();
126     }
127
128     public static @NonNull MapEntryNode mapEntry(final QName nodeName,final QName keyName,final Object keyValue) {
129         return mapEntryBuilder(nodeName, keyName, keyValue).build();
130     }
131
132     /**
133      * Create an immutable container node.
134      *
135      * @param name QName which will be used as node identifier
136      * @return A container node
137      */
138     public static @NonNull ContainerNode containerNode(final QName name) {
139         return ImmutableContainerNodeBuilder.create().withNodeIdentifier(NodeIdentifier.create(name)).build();
140     }
141
142     /**
143      * Create an immutable choice node.
144      *
145      * @param name QName which will be used as node identifier
146      * @return A choice node
147      */
148     public static @NonNull ChoiceNode choiceNode(final QName name) {
149         return ImmutableChoiceNodeBuilder.create().withNodeIdentifier(NodeIdentifier.create(name)).build();
150     }
151
152     /**
153      * Create an immutable list node.
154      *
155      * @param name QName which will be used as node identifier
156      * @return An unkeyed list node
157      */
158     public static @NonNull UnkeyedListNode listNode(final QName name) {
159         return ImmutableUnkeyedListNodeBuilder.create().withNodeIdentifier(NodeIdentifier.create(name)).build();
160     }
161
162     /**
163      * Convert YangInstanceIdentifier into a normalized node structure.
164      *
165      * @param ctx schema context to used during serialization
166      * @param id instance identifier to convert to node structure starting from root
167      * @return serialized normalized node for provided instance Id
168      */
169     public static @NonNull NormalizedNode<?, ?> fromInstanceId(final SchemaContext ctx,
170             final YangInstanceIdentifier id) {
171         return fromInstanceId(ctx, id, Optional.empty(), Optional.empty());
172     }
173
174     /**
175      * Convert YangInstanceIdentifier into a normalized node structure.
176      *
177      * @param ctx schema context to used during serialization
178      * @param id instance identifier to convert to node structure starting from root
179      * @param deepestElement pre-built deepest child that will be inserted at the last path argument of provided
180      *                       instance identifier
181      * @return serialized normalized node for provided instance Id with overridden last child.
182      */
183     public static @NonNull NormalizedNode<?, ?> fromInstanceId(final SchemaContext ctx, final YangInstanceIdentifier id,
184             final NormalizedNode<?, ?> deepestElement) {
185         return fromInstanceId(ctx, id, Optional.of(deepestElement), Optional.empty());
186     }
187
188     /**
189      * Convert YangInstanceIdentifier into a normalized node structure.
190      *
191      * @param ctx schema context to used during serialization
192      * @param id instance identifier to convert to node structure starting from root
193      * @param deepestElement pre-built deepest child that will be inserted at the last path argument of provided
194      *                       instance identifier
195      * @param operation modify operation attribute to be added to the deepest child. QName is the operation attribute
196      *                  key and ModifyAction is the value.
197      * @return serialized normalized node for provided instance Id with (optionally) overridden last child
198      *         and (optionally) marked with specific operation attribute.
199      */
200     public static @NonNull NormalizedNode<?, ?> fromInstanceId(final SchemaContext ctx, final YangInstanceIdentifier id,
201             final Optional<NormalizedNode<?, ?>> deepestElement, final Optional<Entry<QName, ModifyAction>> operation) {
202         final PathArgument topLevelElement;
203         final InstanceIdToNodes<?> instanceIdToNodes;
204         final Iterator<PathArgument> it = id.getPathArguments().iterator();
205         if (it.hasNext()) {
206             topLevelElement = it.next();
207             final DataSchemaNode dataChildByName = ctx.getDataChildByName(topLevelElement.getNodeType());
208             checkNotNull(dataChildByName,
209                 "Cannot find %s node in schema context. Instance identifier has to start from root", topLevelElement);
210             instanceIdToNodes = InstanceIdToNodes.fromSchemaAndQNameChecked(ctx, topLevelElement.getNodeType());
211         } else {
212             topLevelElement = SCHEMACONTEXT_NAME;
213             instanceIdToNodes = InstanceIdToNodes.fromDataSchemaNode(ctx);
214         }
215
216         return instanceIdToNodes.create(topLevelElement, it, deepestElement, operation);
217     }
218 }