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.MoreObjects.ToStringHelper;
13 import com.google.common.base.Verify;
15 import java.util.Map.Entry;
16 import java.util.Optional;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.yangtools.concepts.AbstractIdentifiable;
20 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
23 * Definition / implementation of specific Identifier Namespace behaviour. A namespace behaviour is built on top
24 * of a tree of {@link NamespaceStorageNode} which represents local context of one of types defined
25 * n {@link StorageNodeType}.
28 * For common behaviour models please use static factories {@link #global(Class)}, {@link #sourceLocal(Class)} and
29 * {@link #treeScoped(Class)}.
32 * @param <V> Value type
33 * @param <N> Namespace Type
35 public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K, V>>
36 extends AbstractIdentifiable<Class<N>> {
38 public enum StorageNodeType {
40 * Global storage, visible from all sources.
44 * Storage of the root statement of a particular source and any sources it is importing.
46 // FIXME: 7.0.0: this is a misnomer and should be renamed
49 * Storage of a single statement.
53 * Storage of the root statement of a particular source.
58 public interface Registry {
60 * Get a namespace behavior.
62 * @param type Namespace type class
64 * @param <V> value type
65 * @param <N> namespace type
66 * @return Namespace behaviour
67 * @throws NamespaceNotAvailableException when the namespace is not available
69 <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(Class<N> type);
72 public interface NamespaceStorageNode {
74 * Return local namespace behaviour type.
76 * @return local namespace behaviour type {@link NamespaceBehaviour}
78 StorageNodeType getStorageNodeType();
80 @Nullable NamespaceStorageNode getParentNamespaceStorage();
82 <K, V, N extends IdentifierNamespace<K, V>> @Nullable V getFromLocalStorage(Class<N> type, K key);
84 <K, V, N extends IdentifierNamespace<K, V>> @Nullable Map<K, V> getAllFromLocalStorage(Class<N> type);
87 * Populate specified namespace with a key/value pair, overwriting previous contents. Similar to
88 * {@link Map#put(Object, Object)}.
90 * @param type Namespace identifier
93 * @return Previously-stored value, or null if the key was not present
95 <K, V, N extends IdentifierNamespace<K, V>> @Nullable V putToLocalStorage(Class<N> type, K key, V value);
98 * Populate specified namespace with a key/value pair unless the key is already associated with a value. Similar
99 * to {@link Map#putIfAbsent(Object, Object)}.
101 * @param type Namespace identifier
104 * @return Preexisting value or null if there was no previous mapping
106 <K, V, N extends IdentifierNamespace<K, V>> @Nullable V putToLocalStorageIfAbsent(Class<N> type, K key,
110 protected NamespaceBehaviour(final Class<N> identifier) {
115 * Creates a global namespace behaviour for supplied namespace type. Global behaviour stores and loads all values
116 * from root {@link NamespaceStorageNode} with type of {@link StorageNodeType#GLOBAL}.
118 * @param identifier Namespace identifier.
119 * @param <K> type parameter
120 * @param <V> type parameter
121 * @param <N> type parameter
122 * @return global namespace behaviour for supplied namespace type.
124 public static <K, V, N extends IdentifierNamespace<K, V>> @NonNull NamespaceBehaviour<K, V, N> global(
125 final Class<N> identifier) {
126 return new StorageSpecific<>(identifier, StorageNodeType.GLOBAL);
130 * Creates source-local namespace behaviour for supplied namespace type. Source-local namespace behaviour stores
131 * and loads all values from closest {@link NamespaceStorageNode} ancestor with type
132 * of {@link StorageNodeType#SOURCE_LOCAL_SPECIAL}.
134 * @param identifier Namespace identifier.
135 * @param <K> type parameter
136 * @param <V> type parameter
137 * @param <N> type parameter
138 * @return source-local namespace behaviour for supplied namespace type.
140 public static <K, V, N extends IdentifierNamespace<K, V>> @NonNull NamespaceBehaviour<K, V, N> sourceLocal(
141 final Class<N> identifier) {
142 return new StorageSpecific<>(identifier, StorageNodeType.SOURCE_LOCAL_SPECIAL);
145 public static <K, V, N extends IdentifierNamespace<K, V>> @NonNull NamespaceBehaviour<K, V, N> statementLocal(
146 final Class<N> identifier) {
147 return new StorageSpecific<>(identifier, StorageNodeType.STATEMENT_LOCAL);
151 * Creates a root-statement-local namespace behaviour for supplied namespace type. Root-statement-local namespace
152 * behaviour stores and loads all values from closest {@link NamespaceStorageNode} ancestor with type
153 * of {@link StorageNodeType#ROOT_STATEMENT_LOCAL}.
155 * @param identifier Namespace identifier.
156 * @param <K> type parameter
157 * @param <V> type parameter
158 * @param <N> type parameter
159 * @return root-statement-local namespace behaviour for supplied namespace type.
161 public static <K, V, N extends IdentifierNamespace<K, V>> @NonNull NamespaceBehaviour<K, V, N> rootStatementLocal(
162 final Class<N> identifier) {
163 return new StorageSpecific<>(identifier, StorageNodeType.ROOT_STATEMENT_LOCAL);
167 * Creates tree-scoped namespace behaviour for supplied namespace type. Tree-scoped namespace behaviour searches
168 * for value in all storage nodes up to the root and stores values in supplied node.
171 * Namespace identifier.
172 * @param <K> type parameter
173 * @param <V> type parameter
174 * @param <N> type parameter
175 * @return tree-scoped namespace behaviour for supplied namespace type.
177 public static <K, V, N extends IdentifierNamespace<K, V>> @NonNull NamespaceBehaviour<K, V, N> treeScoped(
178 final Class<N> identifier) {
179 return new TreeScoped<>(identifier);
183 * Returns a value from model namespace storage according to key param class.
185 * @param storage namespace storage
186 * @param key type parameter
187 * @return value from model namespace storage according to key param class
189 public abstract V getFrom(NamespaceStorageNode storage, K key);
192 * Returns the key/value mapping best matching specified criterion.
194 * @param storage namespace storage
195 * @param criterion selection criterion
196 * @return Selected mapping, if available.
198 public final Optional<Entry<K, V>> getFrom(final NamespaceStorageNode storage,
199 final NamespaceKeyCriterion<K> criterion) {
200 final Map<K, V> mappings = getAllFrom(storage);
201 if (mappings == null) {
202 return Optional.empty();
205 Entry<K, V> match = null;
206 for (Entry<K, V> entry : mappings.entrySet()) {
207 final K key = entry.getKey();
208 if (criterion.match(key)) {
210 final K selected = criterion.select(match.getKey(), key);
211 if (selected.equals(match.getKey())) {
215 Verify.verify(selected == key, "Criterion %s selected invalid key %s from candidates [%s %s]",
216 selected, match.getKey(), key);
223 return Optional.ofNullable(match);
227 * Returns all values of a keys of param class from model namespace storage.
229 * @param storage namespace storage
230 * @return all values of keys of param class from model namespace storage
232 public abstract Map<K, V> getAllFrom(NamespaceStorageNode storage);
235 * Adds a key/value to corresponding namespace storage according to param class.
237 * @param storage namespace storage
238 * @param key type parameter
239 * @param value type parameter
241 public abstract void addTo(NamespaceStorageNode storage, K key, V value);
243 protected final V getFromLocalStorage(final NamespaceStorageNode storage, final K key) {
244 return storage.getFromLocalStorage(getIdentifier(), key);
247 protected final Map<K, V> getAllFromLocalStorage(final NamespaceStorageNode storage) {
248 return storage.getAllFromLocalStorage(getIdentifier());
251 protected final void addToStorage(final NamespaceStorageNode storage, final K key, final V value) {
252 storage.putToLocalStorage(getIdentifier(), key, value);
255 static final class StorageSpecific<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
256 StorageNodeType storageType;
258 StorageSpecific(final Class<N> identifier, final StorageNodeType type) {
260 storageType = requireNonNull(type);
264 public V getFrom(final NamespaceStorageNode storage, final K key) {
265 NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
266 return getFromLocalStorage(current, key);
270 public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
271 NamespaceStorageNode current = storage;
272 while (current.getStorageNodeType() != storageType) {
273 current = current.getParentNamespaceStorage();
276 return getAllFromLocalStorage(current);
280 public void addTo(final NamespaceBehaviour.NamespaceStorageNode storage, final K key, final V value) {
281 NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
282 addToStorage(current, key, value);
286 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
287 return super.addToStringAttributes(helper.add("type", storageType));
291 static final class TreeScoped<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
293 TreeScoped(final Class<N> identifier) {
298 public V getFrom(final NamespaceStorageNode storage, final K key) {
299 NamespaceStorageNode current = storage;
300 while (current != null) {
301 final V val = getFromLocalStorage(current, key);
305 current = current.getParentNamespaceStorage();
311 public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
312 NamespaceStorageNode current = storage;
313 while (current != null) {
314 final Map<K, V> val = getAllFromLocalStorage(current);
318 current = current.getParentNamespaceStorage();
324 public void addTo(final NamespaceStorageNode storage, final K key, final V value) {
325 addToStorage(storage, key, value);
330 protected static NamespaceStorageNode findClosestTowardsRoot(final NamespaceStorageNode storage,
331 final StorageNodeType type) {
332 NamespaceStorageNode current = storage;
333 while (current != null && current.getStorageNodeType() != type) {
334 current = current.getParentNamespaceStorage();
340 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
341 return helper.add("identifier", getIdentifier().getName());