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.base.Verify;
14 import java.util.Map.Entry;
15 import java.util.Optional;
16 import javax.annotation.Nonnull;
17 import javax.annotation.Nullable;
18 import org.opendaylight.yangtools.concepts.Identifiable;
19 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
22 * Definition / implementation of specific Identifier Namespace behaviour. A namespace behaviour is built on top
23 * of a tree of {@link NamespaceStorageNode} which represents local context of one of types defined
24 * n {@link StorageNodeType}.
27 * For common behaviour models please use static factories {@link #global(Class)}, {@link #sourceLocal(Class)} and
28 * {@link #treeScoped(Class)}.
37 public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K, V>> implements Identifiable<Class<N>> {
39 public enum StorageNodeType {
40 GLOBAL, SOURCE_LOCAL_SPECIAL, STATEMENT_LOCAL, ROOT_STATEMENT_LOCAL
43 public interface Registry {
45 * Get a namespace behavior.
47 * @param type Namespace type class
49 * @param <V> value type
50 * @param <N> namespace type
51 * @return Namespace behaviour
52 * @throws NamespaceNotAvailableException when the namespace is not available
54 <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(Class<N> type);
57 public interface NamespaceStorageNode {
59 * Return local namespace behaviour type.
61 * @return local namespace behaviour type {@link NamespaceBehaviour}
63 StorageNodeType getStorageNodeType();
66 NamespaceStorageNode getParentNamespaceStorage();
69 <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(Class<N> type, K key);
72 <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromLocalStorage(Class<N> type);
75 * Populate specified namespace with a key/value pair, overwriting previous contents. Similar to
76 * {@link Map#put(Object, Object)}.
78 * @param type Namespace identifier
81 * @return Previously-stored value, or null if the key was not present
84 <K, V, N extends IdentifierNamespace<K, V>> V putToLocalStorage(Class<N> type, K key, V value);
87 * Populate specified namespace with a key/value pair unless the key is already associated with a value. Similar
88 * to {@link Map#putIfAbsent(Object, Object)}.
90 * @param type Namespace identifier
93 * @return Preexisting value or null if there was no previous mapping
96 <K, V, N extends IdentifierNamespace<K, V>> V putToLocalStorageIfAbsent(Class<N> type, K key, V value);
99 private final Class<N> identifier;
101 protected NamespaceBehaviour(final Class<N> identifier) {
102 this.identifier = requireNonNull(identifier);
106 * Creates a global namespace behaviour for supplied namespace type. Global behaviour stores and loads all values
107 * from root {@link NamespaceStorageNode} with type of {@link StorageNodeType#GLOBAL}.
110 * Namespace identifier.
111 * @param <K> type parameter
112 * @param <V> type parameter
113 * @param <N> type parameter
114 * @return global namespace behaviour for supplied namespace type.
116 public static @Nonnull <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> global(
117 final Class<N> identifier) {
118 return new StorageSpecific<>(identifier, StorageNodeType.GLOBAL);
122 * Creates source-local namespace behaviour for supplied namespace type. Source-local namespace behaviour stores
123 * and loads all values from closest {@link NamespaceStorageNode} ancestor with type
124 * of {@link StorageNodeType#SOURCE_LOCAL_SPECIAL}.
127 * Namespace identifier.
128 * @param <K> type parameter
129 * @param <V> type parameter
130 * @param <N> type parameter
131 * @return source-local namespace behaviour for supplied namespace type.
133 public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> sourceLocal(
134 final Class<N> identifier) {
135 return new StorageSpecific<>(identifier, StorageNodeType.SOURCE_LOCAL_SPECIAL);
138 public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> statementLocal(
139 final Class<N> identifier) {
140 return new StorageSpecific<>(identifier, StorageNodeType.STATEMENT_LOCAL);
144 * Creates tree-scoped namespace behaviour for supplied namespace type. Tree-scoped namespace behaviour searches
145 * for value in all storage nodes up to the root and stores values in supplied node.
148 * Namespace identifier.
149 * @param <K> type parameter
150 * @param <V> type parameter
151 * @param <N> type parameter
152 * @return tree-scoped namespace behaviour for supplied namespace type.
154 public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> treeScoped(
155 final Class<N> identifier) {
156 return new TreeScoped<>(identifier);
160 * Returns a value from model namespace storage according to key param class.
162 * @param storage namespace storage
163 * @param key type parameter
164 * @return value from model namespace storage according to key param class
166 public abstract V getFrom(NamespaceStorageNode storage, K key);
169 * Returns the key/value mapping best matching specified criterion.
171 * @param storage namespace storage
172 * @param criterion selection criterion
173 * @return Selected mapping, if available.
175 public final Optional<Entry<K, V>> getFrom(final NamespaceStorageNode storage,
176 final NamespaceKeyCriterion<K> criterion) {
177 final Map<K, V> mappings = getAllFrom(storage);
178 if (mappings == null) {
179 return Optional.empty();
182 Entry<K, V> match = null;
183 for (Entry<K, V> entry : mappings.entrySet()) {
184 final K key = entry.getKey();
185 if (criterion.match(key)) {
187 final K selected = criterion.select(match.getKey(), key);
188 if (selected.equals(match.getKey())) {
192 Verify.verify(selected == key, "Criterion %s selected invalid key %s from candidates [%s %s]",
193 selected, match.getKey(), key);
200 return Optional.ofNullable(match);
204 * Returns all values of a keys of param class from model namespace storage.
206 * @param storage namespace storage
207 * @return all values of keys of param class from model namespace storage
209 public abstract Map<K, V> getAllFrom(NamespaceStorageNode storage);
212 * Adds a key/value to corresponding namespace storage according to param class.
214 * @param storage namespace storage
215 * @param key type parameter
216 * @param value type parameter
218 public abstract void addTo(NamespaceStorageNode storage, K key, V value);
221 public Class<N> getIdentifier() {
225 protected final V getFromLocalStorage(final NamespaceStorageNode storage, final K key) {
226 return storage.getFromLocalStorage(getIdentifier(), key);
229 protected final Map<K, V> getAllFromLocalStorage(final NamespaceStorageNode storage) {
230 return storage.getAllFromLocalStorage(getIdentifier());
233 protected final void addToStorage(final NamespaceStorageNode storage, final K key, final V value) {
234 storage.putToLocalStorage(getIdentifier(), key, value);
237 static final class StorageSpecific<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
238 StorageNodeType storageType;
240 StorageSpecific(final Class<N> identifier, final StorageNodeType type) {
242 storageType = requireNonNull(type);
246 public V getFrom(final NamespaceStorageNode storage, final K key) {
247 NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
248 return getFromLocalStorage(current, key);
252 public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
253 NamespaceStorageNode current = storage;
254 while (current.getStorageNodeType() != storageType) {
255 current = current.getParentNamespaceStorage();
258 return getAllFromLocalStorage(current);
262 public void addTo(final NamespaceBehaviour.NamespaceStorageNode storage, final K key, final V value) {
263 NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
264 addToStorage(current, key, value);
268 static final class TreeScoped<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
270 TreeScoped(final Class<N> identifier) {
275 public V getFrom(final NamespaceStorageNode storage, final K key) {
276 NamespaceStorageNode current = storage;
277 while (current != null) {
278 final V val = getFromLocalStorage(current, key);
282 current = current.getParentNamespaceStorage();
288 public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
289 NamespaceStorageNode current = storage;
290 while (current != null) {
291 final Map<K, V> val = getAllFromLocalStorage(current);
295 current = current.getParentNamespaceStorage();
301 public void addTo(final NamespaceStorageNode storage, final K key, final V value) {
302 addToStorage(storage, key, value);
307 protected static NamespaceStorageNode findClosestTowardsRoot(final NamespaceStorageNode storage,
308 final StorageNodeType type) {
309 NamespaceStorageNode current = storage;
310 while (current != null && current.getStorageNodeType() != type) {
311 current = current.getParentNamespaceStorage();