Move SchemaNodeIdentifier to yang-common
[yangtools.git] / model / yang-model-api / src / main / java / org / opendaylight / yangtools / yang / model / api / stmt / SchemaTreeAwareEffectiveStatement.java
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, 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.model.api.stmt;
9
10 import static java.util.Objects.requireNonNull;
11 import static org.opendaylight.yangtools.yang.model.api.stmt.DefaultMethodHelpers.filterOptional;
12
13 import com.google.common.annotations.Beta;
14 import java.util.Arrays;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.NoSuchElementException;
18 import java.util.Optional;
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.opendaylight.yangtools.yang.common.QName;
22 import org.opendaylight.yangtools.yang.common.SchemaNodeIdentifier;
23 import org.opendaylight.yangtools.yang.common.SchemaNodeIdentifier.Descendant;
24 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
25 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
26
27 /**
28  * Interface implemented by all {@link EffectiveStatement}s which can contain a {@code schema tree} child. This tree
29  * can be walked using {@link SchemaNodeIdentifier}, looking up each component of
30  * {@link SchemaNodeIdentifier#getNodeIdentifiers()} using {@link #findSchemaTreeNode(QName)}.
31  *
32  * @param <A> Argument type
33  * @param <D> Class representing declared version of this statement.
34  * @author Robert Varga
35  */
36 @Beta
37 public interface SchemaTreeAwareEffectiveStatement<A, D extends DeclaredStatement<A>> extends EffectiveStatement<A, D> {
38     /**
39      * Namespace of {@code schema node}s defined within this node.
40      *
41      * @param <T> Child statement type
42      * @author Robert Varga
43      */
44     @NonNullByDefault
45     abstract class Namespace<T extends SchemaTreeEffectiveStatement<?>> extends EffectiveStatementNamespace<T> {
46         private Namespace() {
47             // Should never be instantiated
48         }
49     }
50
51     /**
52      * Find a {@code schema tree} child {@link SchemaTreeEffectiveStatement}, as identified by its QName argument.
53      *
54      * @param qname Child identifier
55      * @return Schema tree child, or empty
56      * @throws NullPointerException if {@code qname} is null
57      */
58     default @NonNull Optional<SchemaTreeEffectiveStatement<?>> findSchemaTreeNode(final @NonNull QName qname) {
59         return get(Namespace.class, requireNonNull(qname));
60     }
61
62     /**
63      * Find a {@code schema tree} child {@link SchemaTreeEffectiveStatement}, as identified by its QName argument.
64      *
65      * @param <E> Effective substatement type
66      * @param type Effective substatement class
67      * @param qname Child identifier
68      * @return Schema tree child, or empty
69      * @throws NullPointerException if any argument is null
70      */
71     default <E> @NonNull Optional<E> findSchemaTreeNode(final @NonNull Class<E> type, final @NonNull QName qname) {
72         return filterOptional(type, findSchemaTreeNode(qname));
73     }
74
75     /**
76      * Find a {@code schema tree} child {@link SchemaTreeEffectiveStatement}, as identified by its QName argument.
77      *
78      * @param qnames Child identifiers
79      * @return Schema tree child, or empty
80      * @throws NullPointerException if {@code qnames} is null or contains a null element
81      * @throws NoSuchElementException if {@code qnames} is empty
82      */
83     default @NonNull Optional<SchemaTreeEffectiveStatement<?>> findSchemaTreeNode(final @NonNull QName... qnames) {
84         return findSchemaTreeNode(Arrays.asList(qnames));
85     }
86
87     /**
88      * Find a {@code schema tree} child {@link SchemaTreeEffectiveStatement}, as identified by its QName argument.
89      *
90      * @param <E> Effective substatement type
91      * @param type Effective substatement class
92      * @param qnames Child identifiers
93      * @return Schema tree child, or empty
94      * @throws NullPointerException if any argument is null or if {@code qnames} contains a null element
95      * @throws NoSuchElementException if {@code qnames} is empty
96      */
97     default <E> @NonNull Optional<E> findSchemaTreeNode(final @NonNull Class<E> type, final @NonNull QName... qnames) {
98         return filterOptional(type, findSchemaTreeNode(Arrays.asList(qnames)));
99     }
100
101     /**
102      * Find a {@code schema tree} child {@link SchemaTreeEffectiveStatement}, as identified by its QName argument.
103      *
104      * @param qnames Child identifiers
105      * @return Schema tree child, or empty
106      * @throws NullPointerException if {@code qnames} is null or contains a null element
107      * @throws NoSuchElementException if {@code qnames} is empty
108      */
109     default @NonNull Optional<SchemaTreeEffectiveStatement<?>> findSchemaTreeNode(final @NonNull List<QName> qnames) {
110         final Iterator<QName> it = qnames.iterator();
111         SchemaTreeAwareEffectiveStatement<?, ?> parent = this;
112         while (true) {
113             final Optional<SchemaTreeEffectiveStatement<?>> found = parent.findSchemaTreeNode(it.next());
114             if (!it.hasNext() || found.isEmpty()) {
115                 return found;
116             }
117             final SchemaTreeEffectiveStatement<?> node = found.orElseThrow();
118             if (node instanceof SchemaTreeAwareEffectiveStatement) {
119                 parent = (SchemaTreeAwareEffectiveStatement<?, ?>) node;
120             } else {
121                 return Optional.empty();
122             }
123         }
124     }
125
126     /**
127      * Find a {@code schema tree} child {@link SchemaTreeEffectiveStatement}, as identified by its QName argument.
128      *
129      * @param <E> Effective substatement type
130      * @param type Effective substatement class
131      * @param qnames Child identifiers
132      * @return Schema tree child, or empty
133      * @throws NullPointerException if {@code qnames} is null or contains a null element
134      * @throws NoSuchElementException if {@code qnames} is empty
135      */
136     default <E> @NonNull Optional<E> findSchemaTreeNode(final @NonNull Class<E> type,
137             final @NonNull List<QName> qnames) {
138         return filterOptional(type, findSchemaTreeNode(qnames));
139     }
140
141     /**
142      * Find a {@code schema tree} child {@link SchemaTreeEffectiveStatement}, as identified by its
143      * {@link Descendant descendant schema node identifier}.
144      *
145      * @implSpec
146      *     Default implementation defers to {@link #findSchemaTreeNode(List)}.
147      *
148      * @param descendant Descendant schema node identifier
149      * @return Schema tree child, or empty
150      * @throws NullPointerException if {@code descendant} is null
151      */
152     default @NonNull Optional<SchemaTreeEffectiveStatement<?>> findSchemaTreeNode(
153             final @NonNull Descendant descendant) {
154         return findSchemaTreeNode(descendant.getNodeIdentifiers());
155     }
156
157     /**
158      * Find a {@code schema tree} child {@link SchemaTreeEffectiveStatement}, as identified by its
159      * {@link Descendant descendant schema node identifier}.
160      *
161      * @implSpec
162      *     Default implementation defers to {@link #findSchemaTreeNode(Class, List)}.
163      *
164      * @param <E> Effective substatement type
165      * @param type Effective substatement class
166      * @param descendant Descendant schema node identifier
167      * @return Schema tree child, or empty
168      * @throws NullPointerException if {@code descendant} is null
169      */
170     default <E> @NonNull Optional<E> findSchemaTreeNode(final @NonNull Class<E> type,
171             final @NonNull Descendant descendant) {
172         return findSchemaTreeNode(type, descendant.getNodeIdentifiers());
173     }
174 }