Import annotations to yang-parser-rfc7950
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / namespace / ChildSchemaNodeNamespace.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.rfc7950.namespace;
9
10 import com.google.common.annotations.Beta;
11 import java.util.Collection;
12 import java.util.Iterator;
13 import java.util.Map;
14 import java.util.Optional;
15 import org.opendaylight.yangtools.yang.common.QName;
16 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
17 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
18 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
19 import org.opendaylight.yangtools.yang.model.api.stmt.UnknownStatement;
20 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
21 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
22 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
23 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
24 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
25
26 /**
27  * Statement local namespace, which holds direct schema node descendants.
28  */
29 @Beta
30 public final class ChildSchemaNodeNamespace<D extends DeclaredStatement<QName>, E extends EffectiveStatement<QName, D>>
31         extends NamespaceBehaviour<QName, StmtContext<?, D, E>, ChildSchemaNodeNamespace<D, E>>
32         implements StatementNamespace<QName, D, E> {
33     public ChildSchemaNodeNamespace() {
34         super((Class) ChildSchemaNodeNamespace.class);
35     }
36
37     @Override
38     public StmtContext<?, D, E> get(final QName key) {
39         // TODO Auto-generated method stub
40         return null;
41     }
42
43     @Override
44     public StmtContext<?, D, E> getFrom(final NamespaceStorageNode storage, final QName key) {
45         // Get the backing storage node for the requested storage
46         final NamespaceStorageNode storageNode = globalOrStatementSpecific(storage);
47         // Check try to look up existing node
48         final StmtContext<?, D, E> existing = storageNode.getFromLocalStorage(getIdentifier(), key);
49
50         // An existing node takes precedence, if it does not exist try to request it
51         return existing != null ? existing : requestFrom(storageNode, key);
52     }
53
54     private static <D extends DeclaredStatement<QName>, E extends EffectiveStatement<QName, D>>
55             StmtContext<?, D, E> requestFrom(final NamespaceStorageNode storageNode, final QName key) {
56         return storageNode instanceof OnDemandSchemaTreeStorageNode
57             ? ((OnDemandSchemaTreeStorageNode) storageNode).requestSchemaTreeChild(key) : null;
58     }
59
60     @Override
61     public Map<QName, StmtContext<?, D, E>> getAllFrom(final NamespaceStorageNode storage) {
62         // TODO Auto-generated method stub
63         return null;
64     }
65
66     @SuppressWarnings("unchecked")
67     @Override
68     public void addTo(final NamespaceStorageNode storage, final QName key, final StmtContext<?, D, E> value) {
69         final StmtContext<?, D, E> prev = globalOrStatementSpecific(storage).putToLocalStorageIfAbsent(
70             ChildSchemaNodeNamespace.class, key, value);
71
72         if (prev != null) {
73             throw new SourceException(value.getStatementSourceReference(),
74                 "Error in module '%s': cannot add '%s'. Node name collision: '%s' already declared at %s",
75                 value.getRoot().rawStatementArgument(), key, prev.getStatementArgument(),
76                 prev.getStatementSourceReference());
77         }
78     }
79
80     /**
81      * Find statement context identified by interpreting specified {@link SchemaNodeIdentifier} starting at specified
82      * {@link StmtContext}.
83      *
84      * @param root Search root context
85      * @param identifier {@link SchemaNodeIdentifier} relative to search root
86      * @return Matching statement context, if present.
87      * @throws NullPointerException if any of the arguments is null
88      */
89     public static Optional<StmtContext<?, ?, ?>> findNode(final StmtContext<?, ?, ?> root,
90             final SchemaNodeIdentifier identifier) {
91         final Iterator<QName> iterator = identifier.getNodeIdentifiers().iterator();
92         if (!iterator.hasNext()) {
93             return Optional.of(root);
94         }
95
96         QName nextPath = iterator.next();
97         @SuppressWarnings("unchecked")
98         StmtContext<?, ?, ?> current = (StmtContext<?, ?, ?>) root.getFromNamespace(ChildSchemaNodeNamespace.class,
99             nextPath);
100         if (current == null) {
101             return Optional.ofNullable(tryToFindUnknownStatement(nextPath.getLocalName(), root));
102         }
103         while (current != null && iterator.hasNext()) {
104             nextPath = iterator.next();
105             @SuppressWarnings("unchecked")
106             final StmtContext<?, ?, ?> nextNodeCtx = (StmtContext<?, ?, ?>) current.getFromNamespace(
107                 ChildSchemaNodeNamespace.class, nextPath);
108             if (nextNodeCtx == null) {
109                 return Optional.ofNullable(tryToFindUnknownStatement(nextPath.getLocalName(), current));
110             }
111             current = nextNodeCtx;
112         }
113         return Optional.ofNullable(current);
114     }
115
116     @SuppressWarnings("unchecked")
117     private static StmtContext<?, ?, ?> tryToFindUnknownStatement(final String localName,
118             final StmtContext<?, ?, ?> current) {
119         final Collection<? extends StmtContext<?, ?, ?>> unknownSubstatements = StmtContextUtils.findAllSubstatements(
120             current, UnknownStatement.class);
121         for (final StmtContext<?, ?, ?> unknownSubstatement : unknownSubstatements) {
122             if (localName.equals(unknownSubstatement.rawStatementArgument())) {
123                 return unknownSubstatement;
124             }
125         }
126         return null;
127     }
128
129     private static NamespaceStorageNode globalOrStatementSpecific(final NamespaceStorageNode storage) {
130         NamespaceStorageNode current = storage;
131         while (!isLocalOrGlobal(current.getStorageNodeType())) {
132             current = current.getParentNamespaceStorage();
133         }
134         return current;
135     }
136
137     private static boolean isLocalOrGlobal(final StorageNodeType type) {
138         return type == StorageNodeType.STATEMENT_LOCAL || type == StorageNodeType.GLOBAL;
139     }
140 }