2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.data.util;
10 import static java.util.Objects.requireNonNull;
12 import org.eclipse.jdt.annotation.NonNull;
13 import org.eclipse.jdt.annotation.Nullable;
14 import org.opendaylight.yangtools.yang.common.QName;
15 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
16 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
17 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
18 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
19 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
20 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.ValueNode;
27 import org.opendaylight.yangtools.yang.data.util.DataSchemaContext.Composite;
28 import org.opendaylight.yangtools.yang.data.util.DataSchemaContext.SimpleValue;
29 import org.opendaylight.yangtools.yang.data.util.impl.context.AbstractCompositeContext;
30 import org.opendaylight.yangtools.yang.data.util.impl.context.AbstractContext;
31 import org.opendaylight.yangtools.yang.data.util.impl.context.AbstractPathMixinContext;
32 import org.opendaylight.yangtools.yang.data.util.impl.context.AbstractValueContext;
33 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
39 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
42 * Schema derived data providing necessary information for mapping between
43 * {@link org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode} and serialization format defined in RFC6020,
44 * since the mapping is not one-to-one.
46 public sealed interface DataSchemaContext permits AbstractContext, Composite, SimpleValue {
48 * A {@link DataSchemaContext} containing other {@link DataSchemaContext}s.
50 sealed interface Composite extends DataSchemaContext permits PathMixin, AbstractCompositeContext {
52 * Find a child node identifier by its {@link PathArgument}.
54 * @param arg Child path argument
55 * @return A child node, or {@code null} if not found
56 * @throws NullPointerException if {@code arg} is {@code null}
58 @Nullable DataSchemaContext childByArg(PathArgument arg);
61 * Find a child node identifier by its {code data tree} {@link QName}. This method returns intermediate nodes
62 * significant from {@link YangInstanceIdentifier} hierarchy of {@link PathArgument}s. If the returned node
63 * indicates is also a {@link PathMixin}, it represents a {@link NormalizedNode} encapsulation which is not
64 * visible in RFC7950 XML encoding, and a further call to this method with the same {@code child} argument will
65 * provide the next step.
67 * @param qname Child data tree QName
68 * @return A child node, or {@code null} if not found
69 * @throws NullPointerException if {@code arg} is {@code null}
71 @Nullable DataSchemaContext childByQName(QName qname);
74 * Find a child node as identified by a {@link YangInstanceIdentifier} relative to this node.
76 * @param path Path towards the child node
77 * @return Child node if present, or empty when corresponding child is not found.
78 * @throws NullPointerException if {@code path} is {@code null}
80 default @Nullable DataSchemaContext childByPath(final @NonNull YangInstanceIdentifier path) {
81 final var it = path.getPathArguments().iterator();
88 final var child = current.childByArg(it.next());
89 if (child == null || !it.hasNext()) {
92 if (!(child instanceof Composite compositeChild)) {
95 current = compositeChild;
100 * Attempt to enter a child {@link DataSchemaContext} towards the {@link DataSchemaNode} child identified by
101 * specified {@code data tree} {@link QName}, adjusting provided {@code stack} with inference steps
102 * corresponding to the transition to the returned node. The stack is expected to be correctly pointing at this
103 * node's schema, otherwise the results of this method are undefined.
105 * @param stack {@link SchemaInferenceStack} to update
106 * @param child Child QName
107 * @return A DataSchemaContextNode on the path towards the specified child
108 * @throws NullPointerException if any argument is {@code null}
110 @Nullable DataSchemaContext enterChild(SchemaInferenceStack stack, QName child);
113 * Attempt to enter a child {@link DataSchemaContext} towards the {@link DataSchemaNode} child identified by
114 * specified {@link PathArgument}, adjusting provided {@code stack} with inference steps corresponding to
115 * the transition to the returned node. The stack is expected to be correctly pointing at this node's schema,
116 * otherwise the results of this method are undefined.
118 * @param stack {@link SchemaInferenceStack} to update
119 * @param child Child path argument
120 * @return A DataSchemaContextNode for the specified child
121 * @throws NullPointerException if any argument is {@code null}
123 @Nullable DataSchemaContext enterChild(SchemaInferenceStack stack, PathArgument child);
127 * This node is a {@link NormalizedNode} intermediate, not represented in RFC7950 XML encoding. This is typically
130 * <li>{@link ChoiceNode} backed by a {@link ChoiceSchemaNode}, or</li>
131 * <li>{@link LeafSetNode} backed by a {@link LeafListSchemaNode}, or</li>
132 * <li>{@link MapNode} backed by a {@link ListSchemaNode} with a non-empty
133 * {@link ListSchemaNode#getKeyDefinition()}, or</li>
134 * <li>{@link UnkeyedListNode} backed by a {@link ListSchemaNode} with an empty
135 * {@link ListSchemaNode#getKeyDefinition()}</li>
139 * This trait is important for XML codec, but also for JSON encoding of {@link YangInstanceIdentifier}.
141 sealed interface PathMixin extends Composite permits AbstractPathMixinContext {
143 * The mixed-in {@link NodeIdentifier}.
145 * @return Mixed-in NodeIdentifier
147 default @NonNull NodeIdentifier mixinPathStep() {
148 return getPathStep();
153 * Marker interface for contexts which boil down to a simple, not-structured {@link ValueNode}. This can be one of
155 * <li>{@link LeafNode} backed by a {@link LeafSchemaNode}, or</li>
156 * <li>{@link LeafSetNode} backed by a {@link LeafListSchemaNode}</li>
160 * This trait interface is exposed for determining that the corresponding {@link TypeDefinition} of the normalized
163 sealed interface SimpleValue extends DataSchemaContext permits AbstractValueContext {
165 * Return the {@link TypeDefinition} of the type backing this context.
167 * @return A {@link TypeDefinition}
169 // FIXME: YANGTOOLS-1528: return yang.data.api.type.NormalizedType
170 @NonNull TypeDefinition<?> type();
174 * Get a {@link DataSchemaContext} for a particular {@link DataSchemaNode}.
176 * @param schema Backing DataSchemaNode
177 * @return A {@link DataSchemaContext}
178 * @throws NullPointerException if {@code schema} is {@code null}
179 * @throws IllegalStateException if {@code schema} is not handled
181 static @NonNull DataSchemaContext of(final DataSchemaNode schema) {
182 return AbstractContext.of(requireNonNull(schema));
185 @NonNull DataSchemaNode dataSchemaNode();
188 * Return the fixed {@link YangInstanceIdentifier} step, if available. This method returns {@code null} for contexts
189 * like {@link MapEntryNode} and {@link LeafSetEntryNode}, where the step depends on the actual node value.
191 * @return A {@link NodeIdentifier}, or {@code null}
193 @Nullable NodeIdentifier pathStep();
196 * Return the fixed {@link YangInstanceIdentifier} step.
198 * @return A {@link NodeIdentifier}
199 * @throws UnsupportedOperationException if this node does not have fixed step
201 default @NonNull NodeIdentifier getPathStep() {
202 final var arg = pathStep();
206 throw new UnsupportedOperationException(this + " does not have a fixed path step");