e5ff14af89b1a5c313639db2f3b85cd54ff06fe5
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / schema / tree / MandatoryDescendant.java
1 /*
2  * Copyright (c) 2021 PANTHEON.tech, s.r.o. 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.tree;
9
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
12
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;
27
28 /**
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.
31  */
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);
35
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;
40
41     private MandatoryDescendant(final YangInstanceIdentifier path, final YangInstanceIdentifier legacyPath) {
42         this.path = requireNonNull(path);
43         this.legacyPath = legacyPath;
44     }
45
46     static @NonNull MandatoryDescendant create(final YangInstanceIdentifier parentId,
47             final DataNodeContainer parentSchema, final DataSchemaNode childSchema) {
48         final NodeIdentifier childId = NodeIdentifier.create(childSchema.getQName());
49
50         if (childSchema.isAugmenting()) {
51             verify(parentSchema instanceof AugmentationTarget, "Unexpected augmenting child %s in non-target %s at %s",
52                 childSchema, parentSchema, parentId);
53
54             final AugmentationSchemaNode aug = ((AugmentationTarget) parentSchema).getAvailableAugmentations().stream()
55                 .filter(augment -> augment.findDataChildByName(childSchema.getQName()).isPresent())
56                 .findFirst()
57                 .orElseThrow(() -> new IllegalArgumentException(String.format(
58                     "Node %s is marked as augmenting but is not present in the schema of %s", childSchema.getQName(),
59                     parentSchema)));
60
61             return new MandatoryDescendant(
62                 parentId.node(DataSchemaContextNode.augmentationIdentifierFrom(aug)).node(childId).toOptimized(),
63                 parentId.node(childId).toOptimized());
64         }
65
66         return new MandatoryDescendant(parentId.node(childId).toOptimized(), null);
67     }
68
69     void enforceOnData(final NormalizedNode<?, ?> data) {
70         // Find try primary path first ...
71         if (NormalizedNodes.findNode(data, path).isPresent()) {
72             return;
73         }
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);
79                 return;
80             }
81         }
82
83         // ... not found, report the error
84         throw new IllegalArgumentException(String.format("Node %s is missing mandatory descendant %s",
85             data.getIdentifier(), path));
86     }
87
88     @Override
89     public String toString() {
90         return legacyPath == null ? path.toString() : "(" + path + " || " + legacyPath + ")";
91     }
92 }