Make ParserNamespace an identifier
[yangtools.git] / parser / yang-parser-spi / src / main / java / org / opendaylight / yangtools / yang / parser / spi / SchemaTreeNamespace.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. 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.parser.spi;
9
10 import com.google.common.annotations.Beta;
11 import java.io.Serial;
12 import java.util.Collection;
13 import java.util.Iterator;
14 import java.util.Optional;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
18 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
19 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
20 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
21 import org.opendaylight.yangtools.yang.model.api.stmt.UnknownStatement;
22 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
23 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
24 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
25
26 /**
27  * Statement local namespace, which holds direct schema node descendants. This corresponds to the contents of the schema
28  * tree as exposed through {@link SchemaTreeAwareEffectiveStatement}.
29  */
30 // FIXME: 7.0.0: this contract seems to fall on the reactor side of things rather than parser-spi. Consider moving this
31 //               into yang-(parser-)reactor-api.
32 @Beta
33 public final class SchemaTreeNamespace<D extends DeclaredStatement<QName>, E extends SchemaTreeEffectiveStatement<D>>
34         extends StatementNamespace<QName, D, E> {
35     @Serial
36     private static final long serialVersionUID = 1L;
37     private static final @NonNull SchemaTreeNamespace<?, ?> INSTANCE = new SchemaTreeNamespace<>();
38
39     private SchemaTreeNamespace() {
40         super("schemaTree");
41     }
42
43     @SuppressWarnings("unchecked")
44     public static <D extends DeclaredStatement<QName>, E extends SchemaTreeEffectiveStatement<D>>
45             @NonNull SchemaTreeNamespace<D, E> instance() {
46         return (SchemaTreeNamespace<D, E>) INSTANCE;
47     }
48
49     /**
50      * Find statement context identified by interpreting specified {@link SchemaNodeIdentifier} starting at specified
51      * {@link StmtContext}.
52      *
53      * @param root Search root context
54      * @param identifier {@link SchemaNodeIdentifier} relative to search root
55      * @return Matching statement context, if present.
56      * @throws NullPointerException if any of the arguments is null
57      */
58     public static Optional<StmtContext<?, ?, ?>> findNode(final StmtContext<?, ?, ?> root,
59             final SchemaNodeIdentifier identifier) {
60         final Iterator<QName> iterator = identifier.getNodeIdentifiers().iterator();
61         if (!iterator.hasNext()) {
62             return Optional.of(root);
63         }
64
65         QName nextPath = iterator.next();
66         StmtContext<?, ?, ?> current = root.getFromNamespace(SchemaTreeNamespace.INSTANCE, nextPath);
67         if (current == null) {
68             return Optional.ofNullable(tryToFindUnknownStatement(nextPath.getLocalName(), root));
69         }
70         while (current != null && iterator.hasNext()) {
71             nextPath = iterator.next();
72             final StmtContext<?, ?, ?> nextNodeCtx = current.getFromNamespace(SchemaTreeNamespace.INSTANCE, nextPath);
73             if (nextNodeCtx == null) {
74                 return Optional.ofNullable(tryToFindUnknownStatement(nextPath.getLocalName(), current));
75             }
76             current = nextNodeCtx;
77         }
78         return Optional.ofNullable(current);
79     }
80
81     @SuppressWarnings("unchecked")
82     private static StmtContext<?, ?, ?> tryToFindUnknownStatement(final String localName,
83             final StmtContext<?, ?, ?> current) {
84         final Collection<? extends StmtContext<?, ?, ?>> unknownSubstatements = StmtContextUtils.findAllSubstatements(
85             current, UnknownStatement.class);
86         for (final StmtContext<?, ?, ?> unknownSubstatement : unknownSubstatements) {
87             if (localName.equals(unknownSubstatement.rawArgument())) {
88                 return unknownSubstatement;
89             }
90         }
91         return null;
92     }
93 }