2 * Copyright (c) 2015 Cisco Systems, Inc. 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.parser.spi.meta;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.Beta;
13 import com.google.common.base.MoreObjects.ToStringHelper;
14 import com.google.common.base.Verify;
16 import java.util.Map.Entry;
17 import java.util.Optional;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.opendaylight.yangtools.concepts.AbstractIdentifiable;
21 import org.opendaylight.yangtools.yang.common.QName;
22 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
23 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
24 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
25 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
26 import org.opendaylight.yangtools.yang.parser.spi.SchemaTreeNamespace;
29 * Definition / implementation of specific Identifier Namespace behaviour. A namespace behaviour is built on top
30 * of a tree of {@link NamespaceStorageNode} which represents local context of one of types defined
31 * n {@link StorageNodeType}.
34 * For common behaviour models please use static factories {@link #global(Class)}, {@link #sourceLocal(Class)} and
35 * {@link #treeScoped(Class)}.
38 * @param <V> Value type
39 * @param <N> Namespace Type
41 public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K, V>>
42 extends AbstractIdentifiable<Class<N>> {
44 public enum StorageNodeType {
46 * Global storage, visible from all sources.
50 * Storage of the root statement of a particular source and any sources it is importing.
52 // FIXME: 7.0.0: this is a misnomer and should be renamed
55 * Storage of a single statement.
59 * Storage of the root statement of a particular source.
64 public interface Registry {
66 * Get a namespace behavior.
68 * @param type Namespace type class
70 * @param <V> value type
71 * @param <N> namespace type
72 * @return Namespace behaviour
73 * @throws NamespaceNotAvailableException when the namespace is not available
75 <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(Class<N> type);
78 public interface NamespaceStorageNode {
80 * Return local namespace behaviour type.
82 * @return local namespace behaviour type {@link NamespaceBehaviour}
84 StorageNodeType getStorageNodeType();
86 @Nullable NamespaceStorageNode getParentNamespaceStorage();
88 <K, V, N extends IdentifierNamespace<K, V>> @Nullable V getFromLocalStorage(Class<N> type, K key);
90 <K, V, N extends IdentifierNamespace<K, V>> @Nullable Map<K, V> getAllFromLocalStorage(Class<N> type);
93 * Populate specified namespace with a key/value pair, overwriting previous contents. Similar to
94 * {@link Map#put(Object, Object)}.
96 * @param type Namespace identifier
99 * @return Previously-stored value, or null if the key was not present
101 <K, V, N extends IdentifierNamespace<K, V>> @Nullable V putToLocalStorage(Class<N> type, K key, V value);
104 * Populate specified namespace with a key/value pair unless the key is already associated with a value. Similar
105 * to {@link Map#putIfAbsent(Object, Object)}.
107 * @param type Namespace identifier
110 * @return Preexisting value or null if there was no previous mapping
112 <K, V, N extends IdentifierNamespace<K, V>> @Nullable V putToLocalStorageIfAbsent(Class<N> type, K key,
117 * Interface implemented by {@link NamespaceStorageNode}s which support dynamic addition of child elements as they
118 * are requested. This means that such a node can, defer creation of child namespace storage nodes, in effect lazily
119 * expanding this namespace on an if-needed basis.
122 public interface OnDemandSchemaTreeStorageNode extends NamespaceStorageNode {
124 * Request that a new member of this node's schema tree statement be added. Implementations are required to
125 * perform lookup in their internal structure and create a child if tractable. Resulting node is expected to
126 * have been registered with local storage, so that it is accessible through
127 * {@link #getFromLocalStorage(Class, Object)}.
130 * This method must not change its mind about a child's presence -- once it returns non-present, it has to be
131 * always returning non-present.
134 * The results produced by this method are expected to be consistent with
135 * {@link SchemaTreeAwareEffectiveStatement#findSchemaTreeNode(QName)} and
136 * {@link SchemaTreeNamespace#getFrom(NamespaceStorageNode, QName)}.
138 * @param qname node identifier of the child being requested
139 * @return Requested child, if it is present.
140 * @throws NullPointerException in {@code qname} is null
142 <D extends DeclaredStatement<QName>, E extends EffectiveStatement<QName, D>>
143 @Nullable StmtContext<QName, D, E> requestSchemaTreeChild(QName qname);
146 protected NamespaceBehaviour(final Class<N> identifier) {
151 * Creates a global namespace behaviour for supplied namespace type. Global behaviour stores and loads all values
152 * from root {@link NamespaceStorageNode} with type of {@link StorageNodeType#GLOBAL}.
154 * @param identifier Namespace identifier.
155 * @param <K> type parameter
156 * @param <V> type parameter
157 * @param <N> type parameter
158 * @return global namespace behaviour for supplied namespace type.
160 public static <K, V, N extends IdentifierNamespace<K, V>> @NonNull NamespaceBehaviour<K, V, N> global(
161 final Class<N> identifier) {
162 return new StorageSpecific<>(identifier, StorageNodeType.GLOBAL);
166 * Creates source-local namespace behaviour for supplied namespace type. Source-local namespace behaviour stores
167 * and loads all values from closest {@link NamespaceStorageNode} ancestor with type
168 * of {@link StorageNodeType#SOURCE_LOCAL_SPECIAL}.
170 * @param identifier Namespace identifier.
171 * @param <K> type parameter
172 * @param <V> type parameter
173 * @param <N> type parameter
174 * @return source-local namespace behaviour for supplied namespace type.
176 public static <K, V, N extends IdentifierNamespace<K, V>> @NonNull NamespaceBehaviour<K, V, N> sourceLocal(
177 final Class<N> identifier) {
178 return new StorageSpecific<>(identifier, StorageNodeType.SOURCE_LOCAL_SPECIAL);
181 public static <K, V, N extends IdentifierNamespace<K, V>> @NonNull NamespaceBehaviour<K, V, N> statementLocal(
182 final Class<N> identifier) {
183 return new StorageSpecific<>(identifier, StorageNodeType.STATEMENT_LOCAL);
187 * Creates a root-statement-local namespace behaviour for supplied namespace type. Root-statement-local namespace
188 * behaviour stores and loads all values from closest {@link NamespaceStorageNode} ancestor with type
189 * of {@link StorageNodeType#ROOT_STATEMENT_LOCAL}.
191 * @param identifier Namespace identifier.
192 * @param <K> type parameter
193 * @param <V> type parameter
194 * @param <N> type parameter
195 * @return root-statement-local namespace behaviour for supplied namespace type.
197 public static <K, V, N extends IdentifierNamespace<K, V>> @NonNull NamespaceBehaviour<K, V, N> rootStatementLocal(
198 final Class<N> identifier) {
199 return new StorageSpecific<>(identifier, StorageNodeType.ROOT_STATEMENT_LOCAL);
203 * Creates tree-scoped namespace behaviour for supplied namespace type. Tree-scoped namespace behaviour searches
204 * for value in all storage nodes up to the root and stores values in supplied node.
207 * Namespace identifier.
208 * @param <K> type parameter
209 * @param <V> type parameter
210 * @param <N> type parameter
211 * @return tree-scoped namespace behaviour for supplied namespace type.
213 public static <K, V, N extends IdentifierNamespace<K, V>> @NonNull NamespaceBehaviour<K, V, N> treeScoped(
214 final Class<N> identifier) {
215 return new TreeScoped<>(identifier);
219 * Returns a value from model namespace storage according to key param class.
221 * @param storage namespace storage
222 * @param key type parameter
223 * @return value from model namespace storage according to key param class
225 public abstract V getFrom(NamespaceStorageNode storage, K key);
228 * Returns the key/value mapping best matching specified criterion.
230 * @param storage namespace storage
231 * @param criterion selection criterion
232 * @return Selected mapping, if available.
234 public final Optional<Entry<K, V>> getFrom(final NamespaceStorageNode storage,
235 final NamespaceKeyCriterion<K> criterion) {
236 final Map<K, V> mappings = getAllFrom(storage);
237 if (mappings == null) {
238 return Optional.empty();
241 Entry<K, V> match = null;
242 for (Entry<K, V> entry : mappings.entrySet()) {
243 final K key = entry.getKey();
244 if (criterion.match(key)) {
246 final K selected = criterion.select(match.getKey(), key);
247 if (selected.equals(match.getKey())) {
251 Verify.verify(selected == key, "Criterion %s selected invalid key %s from candidates [%s %s]",
252 selected, match.getKey(), key);
259 return Optional.ofNullable(match);
263 * Returns all values of a keys of param class from model namespace storage.
265 * @param storage namespace storage
266 * @return all values of keys of param class from model namespace storage
268 public abstract Map<K, V> getAllFrom(NamespaceStorageNode storage);
271 * Adds a key/value to corresponding namespace storage according to param class.
273 * @param storage namespace storage
274 * @param key type parameter
275 * @param value type parameter
277 public abstract void addTo(NamespaceStorageNode storage, K key, V value);
279 protected final V getFromLocalStorage(final NamespaceStorageNode storage, final K key) {
280 return storage.getFromLocalStorage(getIdentifier(), key);
283 protected final Map<K, V> getAllFromLocalStorage(final NamespaceStorageNode storage) {
284 return storage.getAllFromLocalStorage(getIdentifier());
287 protected final void addToStorage(final NamespaceStorageNode storage, final K key, final V value) {
288 storage.putToLocalStorage(getIdentifier(), key, value);
291 static final class StorageSpecific<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
292 private final StorageNodeType storageType;
294 StorageSpecific(final Class<N> identifier, final StorageNodeType type) {
296 storageType = requireNonNull(type);
300 public V getFrom(final NamespaceStorageNode storage, final K key) {
301 NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
302 return getFromLocalStorage(current, key);
306 public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
307 NamespaceStorageNode current = storage;
308 while (current.getStorageNodeType() != storageType) {
309 current = current.getParentNamespaceStorage();
312 return getAllFromLocalStorage(current);
316 public void addTo(final NamespaceBehaviour.NamespaceStorageNode storage, final K key, final V value) {
317 NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
318 addToStorage(current, key, value);
322 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
323 return super.addToStringAttributes(helper.add("type", storageType));
327 static final class TreeScoped<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
329 TreeScoped(final Class<N> identifier) {
334 public V getFrom(final NamespaceStorageNode storage, final K key) {
335 NamespaceStorageNode current = storage;
336 while (current != null) {
337 final V val = getFromLocalStorage(current, key);
341 current = current.getParentNamespaceStorage();
347 public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
348 NamespaceStorageNode current = storage;
349 while (current != null) {
350 final Map<K, V> val = getAllFromLocalStorage(current);
354 current = current.getParentNamespaceStorage();
360 public void addTo(final NamespaceStorageNode storage, final K key, final V value) {
361 addToStorage(storage, key, value);
366 protected static NamespaceStorageNode findClosestTowardsRoot(final NamespaceStorageNode storage,
367 final StorageNodeType type) {
368 NamespaceStorageNode current = storage;
369 while (current != null && current.getStorageNodeType() != type) {
370 current = current.getParentNamespaceStorage();
376 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
377 return helper.add("identifier", getIdentifier().getName());