2 * Copyright (c) 2021 PANTHEON.tech, s.r.o. 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.impl.schema.tree;
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
13 import org.eclipse.jdt.annotation.NonNull;
14 import org.eclipse.jdt.annotation.Nullable;
15 import org.opendaylight.yangtools.concepts.Immutable;
16 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
17 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
18 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
19 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
20 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
21 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
23 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
24 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
29 * A path to a descendant which must exist. This really should be equivalent to YangInstanceIdentifier, but for now we
30 * need to deal with up to two possible paths -- one with AugmentationIdentifiers and one without.
32 // FIXME: 8.0.0: remove this structure and just keep the 'path' YangInstanceIdentifier
33 final class MandatoryDescendant implements Immutable {
34 private static final Logger LOG = LoggerFactory.getLogger(MandatoryDescendant.class);
36 // Correctly-nested path, mirroring Augmentation and choice/case structure
37 private final @NonNull YangInstanceIdentifier path;
38 // Legacy trivial path,
39 private final @Nullable YangInstanceIdentifier legacyPath;
41 private MandatoryDescendant(final YangInstanceIdentifier path, final YangInstanceIdentifier legacyPath) {
42 this.path = requireNonNull(path);
43 this.legacyPath = legacyPath;
46 static @NonNull MandatoryDescendant create(final YangInstanceIdentifier parentId,
47 final DataNodeContainer parentSchema, final DataSchemaNode childSchema) {
48 final NodeIdentifier childId = NodeIdentifier.create(childSchema.getQName());
50 if (childSchema.isAugmenting()) {
51 verify(parentSchema instanceof AugmentationTarget, "Unexpected augmenting child %s in non-target %s at %s",
52 childSchema, parentSchema, parentId);
54 final AugmentationSchemaNode aug = ((AugmentationTarget) parentSchema).getAvailableAugmentations().stream()
55 .filter(augment -> augment.findDataChildByName(childSchema.getQName()).isPresent())
57 .orElseThrow(() -> new IllegalArgumentException(String.format(
58 "Node %s is marked as augmenting but is not present in the schema of %s", childSchema.getQName(),
61 return new MandatoryDescendant(
62 parentId.node(DataSchemaContextNode.augmentationIdentifierFrom(aug)).node(childId).toOptimized(),
63 parentId.node(childId).toOptimized());
66 return new MandatoryDescendant(parentId.node(childId).toOptimized(), null);
69 void enforceOnData(final NormalizedNode data) {
70 // Find try primary path first ...
71 if (NormalizedNodes.findNode(data, path).isPresent()) {
74 // ... if we have a legacy path, try that as well ...
75 if (legacyPath != null) {
76 if (NormalizedNodes.findNode(data, legacyPath).isPresent()) {
77 // .. this should not really be happening ...
78 LOG.debug("Found {} at alternate path {}", path, legacyPath);
83 // ... not found, report the error
84 throw new IllegalArgumentException(String.format("Node %s is missing mandatory descendant %s",
85 data.getIdentifier(), path));
89 public String toString() {
90 return legacyPath == null ? path.toString() : "(" + path + " || " + legacyPath + ")";