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.model.spi;
10 import static com.google.common.base.Preconditions.checkArgument;
12 import com.google.common.annotations.Beta;
13 import com.google.common.annotations.VisibleForTesting;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.collect.Lists;
16 import java.util.Iterator;
17 import java.util.List;
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
21 import org.opendaylight.yangtools.yang.model.api.SchemaTreeInference;
22 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
23 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
24 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
25 import org.opendaylight.yangtools.yang.model.spi.AbstractEffectiveStatementInference.WithPath;
26 import org.slf4j.LoggerFactory;
29 * Default implementation of a {@link SchemaTreeInference}. Guaranteed to be consistent with its
30 * {@link #modelContext()}.
34 public final class DefaultSchemaTreeInference extends WithPath<SchemaTreeEffectiveStatement<?>>
35 implements SchemaTreeInference {
36 private static final String VERIFY_UNSAFE_PROP =
37 "org.opendaylight.yangtools.yang.model.spi.DefaultSchemaTreeInference.verifyUnsafeOf";
38 private static final boolean VERIFY_UNSAFE = Boolean.getBoolean(VERIFY_UNSAFE_PROP);
42 LoggerFactory.getLogger(DefaultSchemaTreeInference.class)
43 .info("DefaultSchemaTreeInference.unsafeOf() arguments are being verified");
47 private DefaultSchemaTreeInference(final EffectiveModelContext modelContext,
48 final ImmutableList<? extends SchemaTreeEffectiveStatement<?>> path) {
49 super(modelContext, path);
53 * Create a new instance based on an {@link EffectiveModelContext} and an {@link Absolute} schema node identifier.
55 * @param modelContext Associated {@link EffectiveModelContext}
56 * @param path An absolute schema node identifier
57 * @return A new instance
58 * @throws NullPointerException if any argument is null
59 * @throws IllegalArgumentException if the provided {@code path} cannot be resolved in {@code modelContext}
61 public static DefaultSchemaTreeInference of(final EffectiveModelContext modelContext, final Absolute path) {
62 return new DefaultSchemaTreeInference(modelContext, resolveSteps(modelContext, path.getNodeIdentifiers()));
66 * Create a new instance based on an {@link EffectiveModelContext} and a resolved sequence of statements. Provided
67 * statements are expected to have been produced in a validated manner and are normally trusted to be accurate.
70 * Run-time verification of {@code path} can be enabled by setting the {@value #VERIFY_UNSAFE_PROP} system property
73 * @param modelContext Associated {@link EffectiveModelContext}
74 * @param path Resolved statement path
75 * @return A new instance
76 * @throws NullPointerException if any argument is null
77 * @throws IllegalArgumentException if {@code path} is empty or when verification is enabled and the {@code path}
78 * does not match the {@code modelContext}'s schema tree
80 public static DefaultSchemaTreeInference unsafeOf(final EffectiveModelContext modelContext,
81 final ImmutableList<? extends SchemaTreeEffectiveStatement<?>> path) {
82 checkArgument(!path.isEmpty(), "Path must not be empty");
83 return VERIFY_UNSAFE ? verifiedOf(modelContext, path) : new DefaultSchemaTreeInference(modelContext, path);
87 static DefaultSchemaTreeInference verifiedOf(final EffectiveModelContext modelContext,
88 final ImmutableList<? extends SchemaTreeEffectiveStatement<?>> path) {
89 final var resolved = resolveSteps(modelContext, Lists.transform(path, SchemaTreeEffectiveStatement::argument));
90 checkArgument(path.equals(resolved), "Provided path %s is not consistent with resolved path %s", path,
92 return new DefaultSchemaTreeInference(modelContext, path);
95 private static ImmutableList<SchemaTreeEffectiveStatement<?>> resolveSteps(final EffectiveModelContext modelContext,
96 final List<QName> steps) {
97 final var first = steps.get(0);
98 final var module = modelContext.findModuleStatement(first.getModule()).orElseThrow(
99 () -> new IllegalArgumentException("No module for " + first));
101 final var builder = ImmutableList.<SchemaTreeEffectiveStatement<?>>builderWithExpectedSize(steps.size());
102 SchemaTreeAwareEffectiveStatement<?, ?> parent = module;
103 final Iterator<QName> it = steps.iterator();
105 final var qname = it.next();
106 final var found = parent.findSchemaTreeNode(qname).orElseThrow(
107 () -> new IllegalArgumentException("Cannot resolve step " + qname + " in " + builder.build()));
114 checkArgument(found instanceof SchemaTreeAwareEffectiveStatement, "Cannot resolve steps %s past %s", steps,
116 parent = (SchemaTreeAwareEffectiveStatement<?, ?>) found;
119 return builder.build();