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 {
44 <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(Class<N> type);
47 public interface NamespaceStorageNode {
49 * Return local namespace behaviour type.
51 * @return local namespace behaviour type {@link NamespaceBehaviour}
53 StorageNodeType getStorageNodeType();
56 NamespaceStorageNode getParentNamespaceStorage();
59 <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(Class<N> type, K key);
62 <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromLocalStorage(Class<N> type);
65 * Populate specified namespace with a key/value pair, overwriting previous contents. Similar to
66 * {@link Map#put(Object, Object)}.
68 * @param type Namespace identifier
71 * @return Previously-stored value, or null if the key was not present
74 <K, V, N extends IdentifierNamespace<K, V>> V putToLocalStorage(Class<N> type, K key, V value);
77 * Populate specified namespace with a key/value pair unless the key is already associated with a value. Similar
78 * to {@link Map#putIfAbsent(Object, Object)}.
80 * @param type Namespace identifier
83 * @return Preexisting value or null if there was no previous mapping
86 <K, V, N extends IdentifierNamespace<K, V>> V putToLocalStorageIfAbsent(Class<N> type, K key, V value);
89 private final Class<N> identifier;
91 protected NamespaceBehaviour(final Class<N> identifier) {
92 this.identifier = requireNonNull(identifier);
96 * Creates a global namespace behaviour for supplied namespace type. Global behaviour stores and loads all values
97 * from root {@link NamespaceStorageNode} with type of {@link StorageNodeType#GLOBAL}.
100 * Namespace identifier.
101 * @param <K> type parameter
102 * @param <V> type parameter
103 * @param <N> type parameter
104 * @return global namespace behaviour for supplied namespace type.
106 public static @Nonnull <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> global(
107 final Class<N> identifier) {
108 return new StorageSpecific<>(identifier, StorageNodeType.GLOBAL);
112 * Creates source-local namespace behaviour for supplied namespace type. Source-local namespace behaviour stores
113 * and loads all values from closest {@link NamespaceStorageNode} ancestor with type
114 * of {@link StorageNodeType#SOURCE_LOCAL_SPECIAL}.
117 * Namespace identifier.
118 * @param <K> type parameter
119 * @param <V> type parameter
120 * @param <N> type parameter
121 * @return source-local namespace behaviour for supplied namespace type.
123 public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> sourceLocal(
124 final Class<N> identifier) {
125 return new StorageSpecific<>(identifier, StorageNodeType.SOURCE_LOCAL_SPECIAL);
128 public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> statementLocal(
129 final Class<N> identifier) {
130 return new StorageSpecific<>(identifier, StorageNodeType.STATEMENT_LOCAL);
134 * Creates tree-scoped namespace behaviour for supplied namespace type. Tree-scoped namespace behaviour searches
135 * for value in all storage nodes up to the root and stores values in supplied node.
138 * Namespace identifier.
139 * @param <K> type parameter
140 * @param <V> type parameter
141 * @param <N> type parameter
142 * @return tree-scoped namespace behaviour for supplied namespace type.
144 public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> treeScoped(
145 final Class<N> identifier) {
146 return new TreeScoped<>(identifier);
150 * Returns a value from model namespace storage according to key param class.
152 * @param storage namespace storage
153 * @param key type parameter
154 * @return value from model namespace storage according to key param class
156 public abstract V getFrom(NamespaceStorageNode storage, K key);
159 * Returns the key/value mapping best matching specified criterion.
161 * @param storage namespace storage
162 * @param criterion selection criterion
163 * @return Selected mapping, if available.
165 public final Optional<Entry<K, V>> getFrom(final NamespaceStorageNode storage,
166 final NamespaceKeyCriterion<K> criterion) {
167 final Map<K, V> mappings = getAllFrom(storage);
168 if (mappings == null) {
169 return Optional.empty();
172 Entry<K, V> match = null;
173 for (Entry<K, V> entry : mappings.entrySet()) {
174 final K key = entry.getKey();
175 if (criterion.match(key)) {
177 final K selected = criterion.select(match.getKey(), key);
178 if (selected.equals(match.getKey())) {
182 Verify.verify(selected == key, "Criterion %s selected invalid key %s from candidates [%s %s]",
183 selected, match.getKey(), key);
190 return Optional.ofNullable(match);
194 * Returns all values of a keys of param class from model namespace storage.
196 * @param storage namespace storage
197 * @return all values of keys of param class from model namespace storage
199 public abstract Map<K, V> getAllFrom(NamespaceStorageNode storage);
202 * Adds a key/value to corresponding namespace storage according to param class.
204 * @param storage namespace storage
205 * @param key type parameter
206 * @param value type parameter
208 public abstract void addTo(NamespaceStorageNode storage, K key, V value);
211 public Class<N> getIdentifier() {
215 protected final V getFromLocalStorage(final NamespaceStorageNode storage, final K key) {
216 return storage.getFromLocalStorage(getIdentifier(), key);
219 protected final Map<K, V> getAllFromLocalStorage(final NamespaceStorageNode storage) {
220 return storage.getAllFromLocalStorage(getIdentifier());
223 protected final void addToStorage(final NamespaceStorageNode storage, final K key, final V value) {
224 storage.putToLocalStorage(getIdentifier(), key, value);
227 static final class StorageSpecific<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
228 StorageNodeType storageType;
230 StorageSpecific(final Class<N> identifier, final StorageNodeType type) {
232 storageType = requireNonNull(type);
236 public V getFrom(final NamespaceStorageNode storage, final K key) {
237 NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
238 return getFromLocalStorage(current, key);
242 public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
243 NamespaceStorageNode current = storage;
244 while (current.getStorageNodeType() != storageType) {
245 current = current.getParentNamespaceStorage();
248 return getAllFromLocalStorage(current);
252 public void addTo(final NamespaceBehaviour.NamespaceStorageNode storage, final K key, final V value) {
253 NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
254 addToStorage(current, key, value);
258 static final class TreeScoped<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
260 TreeScoped(final Class<N> identifier) {
265 public V getFrom(final NamespaceStorageNode storage, final K key) {
266 NamespaceStorageNode current = storage;
267 while (current != null) {
268 final V val = getFromLocalStorage(current, key);
272 current = current.getParentNamespaceStorage();
278 public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
279 NamespaceStorageNode current = storage;
280 while (current != null) {
281 final Map<K, V> val = getAllFromLocalStorage(current);
285 current = current.getParentNamespaceStorage();
291 public void addTo(final NamespaceStorageNode storage, final K key, final V value) {
292 addToStorage(storage, key, value);
297 protected static NamespaceStorageNode findClosestTowardsRoot(final NamespaceStorageNode storage,
298 final StorageNodeType type) {
299 NamespaceStorageNode current = storage;
300 while (current != null && current.getStorageNodeType() != type) {
301 current = current.getParentNamespaceStorage();