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;
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 javax.annotation.Nonnull;
19 import javax.annotation.Nullable;
20 import org.opendaylight.yangtools.concepts.Identifiable;
21 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
24 * Definition / implementation of specific Identifier Namespace behaviour. A namespace behaviour is built on top
25 * of a tree of {@link NamespaceStorageNode} which represents local context of one of types defined
26 * n {@link StorageNodeType}.
29 * For common behaviour models please use static factories {@link #global(Class)}, {@link #sourceLocal(Class)} and
30 * {@link #treeScoped(Class)}.
39 public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K, V>> implements Identifiable<Class<N>> {
41 public enum StorageNodeType {
43 * Global storage, visible from all sources.
47 * Storage of the root statement of a particular source and any sources it is importing.
49 // FIXME: 3.0.0: this is a misnomer and should be renamed
52 * Storage of a single statement.
56 * Storage of the root statement of a particular source.
61 public interface Registry {
63 * Get a namespace behavior.
65 * @param type Namespace type class
67 * @param <V> value type
68 * @param <N> namespace type
69 * @return Namespace behaviour
70 * @throws NamespaceNotAvailableException when the namespace is not available
72 <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(Class<N> type);
75 public interface NamespaceStorageNode {
77 * Return local namespace behaviour type.
79 * @return local namespace behaviour type {@link NamespaceBehaviour}
81 StorageNodeType getStorageNodeType();
84 NamespaceStorageNode getParentNamespaceStorage();
87 <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(Class<N> type, K key);
90 <K, V, N extends IdentifierNamespace<K, V>> 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
102 <K, V, N extends IdentifierNamespace<K, V>> V putToLocalStorage(Class<N> type, K key, V value);
105 * Populate specified namespace with a key/value pair unless the key is already associated with a value. Similar
106 * to {@link Map#putIfAbsent(Object, Object)}.
108 * @param type Namespace identifier
111 * @return Preexisting value or null if there was no previous mapping
114 <K, V, N extends IdentifierNamespace<K, V>> V putToLocalStorageIfAbsent(Class<N> type, K key, V value);
117 private final Class<N> identifier;
119 protected NamespaceBehaviour(final Class<N> identifier) {
120 this.identifier = requireNonNull(identifier);
124 * Creates a global namespace behaviour for supplied namespace type. Global behaviour stores and loads all values
125 * from root {@link NamespaceStorageNode} with type of {@link StorageNodeType#GLOBAL}.
128 * Namespace identifier.
129 * @param <K> type parameter
130 * @param <V> type parameter
131 * @param <N> type parameter
132 * @return global namespace behaviour for supplied namespace type.
134 public static @Nonnull <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> global(
135 final Class<N> identifier) {
136 return new StorageSpecific<>(identifier, StorageNodeType.GLOBAL);
140 * Creates source-local namespace behaviour for supplied namespace type. Source-local namespace behaviour stores
141 * and loads all values from closest {@link NamespaceStorageNode} ancestor with type
142 * of {@link StorageNodeType#SOURCE_LOCAL_SPECIAL}.
145 * Namespace identifier.
146 * @param <K> type parameter
147 * @param <V> type parameter
148 * @param <N> type parameter
149 * @return source-local namespace behaviour for supplied namespace type.
151 public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> sourceLocal(
152 final Class<N> identifier) {
153 return new StorageSpecific<>(identifier, StorageNodeType.SOURCE_LOCAL_SPECIAL);
156 public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> statementLocal(
157 final Class<N> identifier) {
158 return new StorageSpecific<>(identifier, StorageNodeType.STATEMENT_LOCAL);
162 * Creates a root-statement-local namespace behaviour for supplied namespace type. Root-statement-local namespace
163 * behaviour stores and loads all values from closest {@link NamespaceStorageNode} ancestor with type
164 * of {@link StorageNodeType#ROOT_STATEMENT_LOCAL}.
167 * Namespace identifier.
168 * @param <K> type parameter
169 * @param <V> type parameter
170 * @param <N> type parameter
171 * @return root-statement-local namespace behaviour for supplied namespace type.
173 public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> rootStatementLocal(
174 final Class<N> identifier) {
175 return new StorageSpecific<>(identifier, StorageNodeType.ROOT_STATEMENT_LOCAL);
179 * Creates tree-scoped namespace behaviour for supplied namespace type. Tree-scoped namespace behaviour searches
180 * for value in all storage nodes up to the root and stores values in supplied node.
183 * Namespace identifier.
184 * @param <K> type parameter
185 * @param <V> type parameter
186 * @param <N> type parameter
187 * @return tree-scoped namespace behaviour for supplied namespace type.
189 public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> treeScoped(
190 final Class<N> identifier) {
191 return new TreeScoped<>(identifier);
195 * Returns a value from model namespace storage according to key param class.
197 * @param storage namespace storage
198 * @param key type parameter
199 * @return value from model namespace storage according to key param class
201 public abstract V getFrom(NamespaceStorageNode storage, K key);
204 * Returns the key/value mapping best matching specified criterion.
206 * @param storage namespace storage
207 * @param criterion selection criterion
208 * @return Selected mapping, if available.
210 public final Optional<Entry<K, V>> getFrom(final NamespaceStorageNode storage,
211 final NamespaceKeyCriterion<K> criterion) {
212 final Map<K, V> mappings = getAllFrom(storage);
213 if (mappings == null) {
214 return Optional.empty();
217 Entry<K, V> match = null;
218 for (Entry<K, V> entry : mappings.entrySet()) {
219 final K key = entry.getKey();
220 if (criterion.match(key)) {
222 final K selected = criterion.select(match.getKey(), key);
223 if (selected.equals(match.getKey())) {
227 Verify.verify(selected == key, "Criterion %s selected invalid key %s from candidates [%s %s]",
228 selected, match.getKey(), key);
235 return Optional.ofNullable(match);
239 * Returns all values of a keys of param class from model namespace storage.
241 * @param storage namespace storage
242 * @return all values of keys of param class from model namespace storage
244 public abstract Map<K, V> getAllFrom(NamespaceStorageNode storage);
247 * Adds a key/value to corresponding namespace storage according to param class.
249 * @param storage namespace storage
250 * @param key type parameter
251 * @param value type parameter
253 public abstract void addTo(NamespaceStorageNode storage, K key, V value);
256 public Class<N> getIdentifier() {
260 protected final V getFromLocalStorage(final NamespaceStorageNode storage, final K key) {
261 return storage.getFromLocalStorage(getIdentifier(), key);
264 protected final Map<K, V> getAllFromLocalStorage(final NamespaceStorageNode storage) {
265 return storage.getAllFromLocalStorage(getIdentifier());
268 protected final void addToStorage(final NamespaceStorageNode storage, final K key, final V value) {
269 storage.putToLocalStorage(getIdentifier(), key, value);
272 static final class StorageSpecific<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
273 StorageNodeType storageType;
275 StorageSpecific(final Class<N> identifier, final StorageNodeType type) {
277 storageType = requireNonNull(type);
281 public V getFrom(final NamespaceStorageNode storage, final K key) {
282 NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
283 return getFromLocalStorage(current, key);
287 public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
288 NamespaceStorageNode current = storage;
289 while (current.getStorageNodeType() != storageType) {
290 current = current.getParentNamespaceStorage();
293 return getAllFromLocalStorage(current);
297 public void addTo(final NamespaceBehaviour.NamespaceStorageNode storage, final K key, final V value) {
298 NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
299 addToStorage(current, key, value);
303 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
304 return super.addToStringAttributes(helper.add("type", storageType));
308 static final class TreeScoped<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
310 TreeScoped(final Class<N> identifier) {
315 public V getFrom(final NamespaceStorageNode storage, final K key) {
316 NamespaceStorageNode current = storage;
317 while (current != null) {
318 final V val = getFromLocalStorage(current, key);
322 current = current.getParentNamespaceStorage();
328 public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
329 NamespaceStorageNode current = storage;
330 while (current != null) {
331 final Map<K, V> val = getAllFromLocalStorage(current);
335 current = current.getParentNamespaceStorage();
341 public void addTo(final NamespaceStorageNode storage, final K key, final V value) {
342 addToStorage(storage, key, value);
347 protected static NamespaceStorageNode findClosestTowardsRoot(final NamespaceStorageNode storage,
348 final StorageNodeType type) {
349 NamespaceStorageNode current = storage;
350 while (current != null && current.getStorageNodeType() != type) {
351 current = current.getParentNamespaceStorage();
357 // FIXME: 3.0.0: make this final
358 public String toString() {
359 return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
362 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
363 return helper.add("identifier", identifier.getName());