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 com.google.common.collect.FluentIterable;
11 import com.google.common.collect.ImmutableSet;
12 import java.util.List;
13 import java.util.Optional;
15 import javax.annotation.Nullable;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.opendaylight.yangtools.concepts.Identifiable;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
22 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
25 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
29 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
34 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
35 import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
38 * Schema derived data providing necessary information for mapping between
39 * {@link org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode} and serialization format defined in RFC6020,
40 * since the mapping is not one-to-one.
42 * @param <T> Path Argument type
44 public abstract class DataSchemaContextNode<T extends PathArgument> implements Identifiable<T> {
45 private final DataSchemaNode dataSchemaNode;
46 private final T identifier;
48 protected DataSchemaContextNode(final T identifier, final SchemaNode schema) {
49 this.identifier = identifier;
50 if (schema instanceof DataSchemaNode) {
51 this.dataSchemaNode = (DataSchemaNode) schema;
53 this.dataSchemaNode = null;
58 public T getIdentifier() {
62 public boolean isMixin() {
66 public boolean isKeyedEntry() {
70 public abstract boolean isLeaf();
72 protected Set<QName> getQNameIdentifiers() {
73 return ImmutableSet.of(identifier.getNodeType());
77 * Find a child node identifier by its {@link PathArgument}.
79 * @param child Child path argument
80 * @return A child node, or null if not found
82 @Nullable public abstract DataSchemaContextNode<?> getChild(PathArgument child);
84 @Nullable public abstract DataSchemaContextNode<?> getChild(QName child);
86 @Nullable public DataSchemaNode getDataSchemaNode() {
87 return dataSchemaNode;
91 * Find a child node as identified by a {@link YangInstanceIdentifier} relative to this node.
93 * @param path Path towards the child node
94 * @return Child node if present, or empty when corresponding child is not found.
95 * @throws NullPointerException if {@code path} is null
97 public final @NonNull Optional<@NonNull DataSchemaContextNode<?>> findChild(
98 final @NonNull YangInstanceIdentifier path) {
99 DataSchemaContextNode<?> currentOp = this;
100 for (PathArgument arg : path.getPathArguments()) {
101 currentOp = currentOp.getChild(arg);
102 if (currentOp == null) {
103 return Optional.empty();
106 return Optional.of(currentOp);
109 static DataSchemaNode findChildSchemaNode(final DataNodeContainer parent, final QName child) {
110 DataSchemaNode potential = parent.getDataChildByName(child);
111 if (potential == null) {
112 Iterable<ChoiceSchemaNode> choices = FluentIterable.from(
113 parent.getChildNodes()).filter(ChoiceSchemaNode.class);
114 potential = findChoice(choices, child);
119 static DataSchemaContextNode<?> fromSchemaAndQNameChecked(final DataNodeContainer schema, final QName child) {
120 DataSchemaNode result = findChildSchemaNode(schema, child);
121 // We try to look up if this node was added by augmentation
122 if (result != null && schema instanceof DataSchemaNode && result.isAugmenting()) {
123 return fromAugmentation(schema, (AugmentationTarget) schema, result);
125 return fromDataSchemaNode(result);
128 // FIXME: this looks like it should be a Predicate on a stream with findFirst()
129 private static ChoiceSchemaNode findChoice(final Iterable<ChoiceSchemaNode> choices, final QName child) {
130 for (ChoiceSchemaNode choice : choices) {
131 // FIXME: this looks weird: what are we looking for again?
132 for (CaseSchemaNode caze : choice.getCases().values()) {
133 if (findChildSchemaNode(caze, child) != null) {
141 public static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchemaNode augmentation) {
142 ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
143 for (DataSchemaNode child : augmentation.getChildNodes()) {
144 potentialChildren.add(child.getQName());
146 return new AugmentationIdentifier(potentialChildren.build());
150 * Returns an AugmentationSchemaNode as effective in a parent node.
152 * @param schema Augmentation schema
153 * @param parent Parent schema
154 * @return Adjusted Augmentation schema
155 * @throws NullPointerException if any of the arguments is null
156 * @deprecated Use {@link EffectiveAugmentationSchema#create(AugmentationSchemaNode, DataNodeContainer)} instead.
159 public static AugmentationSchemaNode augmentationProxy(final AugmentationSchemaNode schema,
160 final DataNodeContainer parent) {
161 return EffectiveAugmentationSchema.create(schema, parent);
165 * Returns a DataContextNodeOperation for provided child node
168 * If supplied child is added by Augmentation this operation returns a
169 * DataContextNodeOperation for augmentation, otherwise returns a
170 * DataContextNodeOperation for child as call for
171 * {@link #fromDataSchemaNode(DataSchemaNode)}.
173 @Nullable static DataSchemaContextNode<?> fromAugmentation(final DataNodeContainer parent,
174 final AugmentationTarget parentAug, final DataSchemaNode child) {
175 AugmentationSchemaNode augmentation = null;
176 for (AugmentationSchemaNode aug : parentAug.getAvailableAugmentations()) {
177 DataSchemaNode potential = aug.getDataChildByName(child.getQName());
178 if (potential != null) {
183 if (augmentation != null) {
184 return new AugmentationContextNode(augmentation, parent);
186 return fromDataSchemaNode(child);
189 @Nullable public static DataSchemaContextNode<?> fromDataSchemaNode(final DataSchemaNode potential) {
190 if (potential instanceof ContainerSchemaNode) {
191 return new ContainerContextNode((ContainerSchemaNode) potential);
192 } else if (potential instanceof ListSchemaNode) {
193 return fromListSchemaNode((ListSchemaNode) potential);
194 } else if (potential instanceof LeafSchemaNode) {
195 return new LeafContextNode((LeafSchemaNode) potential);
196 } else if (potential instanceof ChoiceSchemaNode) {
197 return new ChoiceNodeContextNode((ChoiceSchemaNode) potential);
198 } else if (potential instanceof LeafListSchemaNode) {
199 return fromLeafListSchemaNode((LeafListSchemaNode) potential);
200 } else if (potential instanceof AnyXmlSchemaNode) {
201 return new AnyXmlContextNode((AnyXmlSchemaNode) potential);
206 private static DataSchemaContextNode<?> fromListSchemaNode(final ListSchemaNode potential) {
207 List<QName> keyDefinition = potential.getKeyDefinition();
208 if (keyDefinition == null || keyDefinition.isEmpty()) {
209 return new UnkeyedListMixinContextNode(potential);
211 if (potential.isUserOrdered()) {
212 return new OrderedMapMixinContextNode(potential);
214 return new UnorderedMapMixinContextNode(potential);
217 private static DataSchemaContextNode<?> fromLeafListSchemaNode(final LeafListSchemaNode potential) {
218 if (potential.isUserOrdered()) {
219 return new OrderedLeafListMixinContextNode(potential);
221 return new UnorderedLeafListMixinContextNode(potential);
224 public static DataSchemaContextNode<?> from(final SchemaContext ctx) {
225 return new ContainerContextNode(ctx);