Revert "Add OnDemandSchemaTreeStorageNode"
[yangtools.git] / yang / yang-parser-spi / src / main / java / org / opendaylight / yangtools / yang / parser / spi / meta / NamespaceBehaviour.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.parser.spi.meta;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.base.MoreObjects.ToStringHelper;
13 import com.google.common.base.Verify;
14 import java.util.Map;
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;
21
22 /**
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}.
26  *
27  * <p>
28  * For common behaviour models please use static factories {@link #global(Class)}, {@link #sourceLocal(Class)} and
29  * {@link #treeScoped(Class)}.
30  *
31  * @param <K> Key type
32  * @param <V> Value type
33  * @param <N> Namespace Type
34  */
35 public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K, V>>
36         extends AbstractIdentifiable<Class<N>> {
37
38     public enum StorageNodeType {
39         /**
40          * Global storage, visible from all sources.
41          */
42         GLOBAL,
43         /**
44          * Storage of the root statement of a particular source and any sources it is importing.
45          */
46         // FIXME: 7.0.0: this is a misnomer and should be renamed
47         SOURCE_LOCAL_SPECIAL,
48         /**
49          * Storage of a single statement.
50          */
51         STATEMENT_LOCAL,
52         /**
53          * Storage of the root statement of a particular source.
54          */
55         ROOT_STATEMENT_LOCAL
56     }
57
58     public interface Registry {
59         /**
60          * Get a namespace behavior.
61          *
62          * @param type Namespace type class
63          * @param <K> key type
64          * @param <V> value type
65          * @param <N> namespace type
66          * @return Namespace behaviour
67          * @throws NamespaceNotAvailableException when the namespace is not available
68          */
69         <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(Class<N> type);
70     }
71
72     public interface NamespaceStorageNode {
73         /**
74          * Return local namespace behaviour type.
75          *
76          * @return local namespace behaviour type {@link NamespaceBehaviour}
77          */
78         StorageNodeType getStorageNodeType();
79
80         @Nullable NamespaceStorageNode getParentNamespaceStorage();
81
82         <K, V, N extends IdentifierNamespace<K, V>> @Nullable V getFromLocalStorage(Class<N> type, K key);
83
84         <K, V, N extends IdentifierNamespace<K, V>> @Nullable Map<K, V> getAllFromLocalStorage(Class<N> type);
85
86         /**
87          * Populate specified namespace with a key/value pair, overwriting previous contents. Similar to
88          * {@link Map#put(Object, Object)}.
89          *
90          * @param type Namespace identifier
91          * @param key Key
92          * @param value Value
93          * @return Previously-stored value, or null if the key was not present
94          */
95         <K, V, N extends IdentifierNamespace<K, V>> @Nullable V putToLocalStorage(Class<N> type, K key, V value);
96
97         /**
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)}.
100          *
101          * @param type Namespace identifier
102          * @param key Key
103          * @param value Value
104          * @return Preexisting value or null if there was no previous mapping
105          */
106         <K, V, N extends IdentifierNamespace<K, V>> @Nullable V putToLocalStorageIfAbsent(Class<N> type, K key,
107                 V value);
108     }
109
110     protected NamespaceBehaviour(final Class<N> identifier) {
111         super(identifier);
112     }
113
114     /**
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}.
117      *
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.
123      */
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);
127     }
128
129     /**
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}.
133      *
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.
139      */
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);
143     }
144
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);
148     }
149
150     /**
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}.
154      *
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.
160      */
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);
164     }
165
166     /**
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.
169      *
170      * @param identifier
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.
176      */
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);
180     }
181
182     /**
183      * Returns a value from model namespace storage according to key param class.
184      *
185      * @param storage namespace storage
186      * @param key type parameter
187      * @return value from model namespace storage according to key param class
188      */
189     public abstract V getFrom(NamespaceStorageNode storage, K key);
190
191     /**
192      * Returns the key/value mapping best matching specified criterion.
193      *
194      * @param storage namespace storage
195      * @param criterion selection criterion
196      * @return Selected mapping, if available.
197      */
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();
203         }
204
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)) {
209                 if (match != null) {
210                     final K selected = criterion.select(match.getKey(), key);
211                     if (selected.equals(match.getKey())) {
212                         continue;
213                     }
214
215                     Verify.verify(selected == key, "Criterion %s selected invalid key %s from candidates [%s %s]",
216                             selected, match.getKey(), key);
217                 }
218
219                 match = entry;
220             }
221         }
222
223         return Optional.ofNullable(match);
224     }
225
226     /**
227      * Returns all values of a keys of param class from model namespace storage.
228      *
229      * @param storage namespace storage
230      * @return all values of keys of param class from model namespace storage
231      */
232     public abstract Map<K, V> getAllFrom(NamespaceStorageNode storage);
233
234     /**
235      * Adds a key/value to corresponding namespace storage according to param class.
236      *
237      * @param storage namespace storage
238      * @param key type parameter
239      * @param value type parameter
240      */
241     public abstract void addTo(NamespaceStorageNode storage, K key, V value);
242
243     protected final V getFromLocalStorage(final NamespaceStorageNode storage, final K key) {
244         return storage.getFromLocalStorage(getIdentifier(), key);
245     }
246
247     protected final Map<K, V> getAllFromLocalStorage(final NamespaceStorageNode storage) {
248         return storage.getAllFromLocalStorage(getIdentifier());
249     }
250
251     protected final void addToStorage(final NamespaceStorageNode storage, final K key, final V value) {
252         storage.putToLocalStorage(getIdentifier(), key, value);
253     }
254
255     static final class StorageSpecific<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
256         StorageNodeType storageType;
257
258         StorageSpecific(final Class<N> identifier, final StorageNodeType type) {
259             super(identifier);
260             storageType = requireNonNull(type);
261         }
262
263         @Override
264         public V getFrom(final NamespaceStorageNode storage, final K key) {
265             NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
266             return getFromLocalStorage(current, key);
267         }
268
269         @Override
270         public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
271             NamespaceStorageNode current = storage;
272             while (current.getStorageNodeType() != storageType) {
273                 current = current.getParentNamespaceStorage();
274             }
275
276             return getAllFromLocalStorage(current);
277         }
278
279         @Override
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);
283         }
284
285         @Override
286         protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
287             return super.addToStringAttributes(helper.add("type", storageType));
288         }
289     }
290
291     static final class TreeScoped<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
292
293         TreeScoped(final Class<N> identifier) {
294             super(identifier);
295         }
296
297         @Override
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);
302                 if (val != null) {
303                     return val;
304                 }
305                 current = current.getParentNamespaceStorage();
306             }
307             return null;
308         }
309
310         @Override
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);
315                 if (val != null) {
316                     return val;
317                 }
318                 current = current.getParentNamespaceStorage();
319             }
320             return null;
321         }
322
323         @Override
324         public void addTo(final NamespaceStorageNode storage, final K key, final V value) {
325             addToStorage(storage, key, value);
326         }
327
328     }
329
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();
335         }
336         return current;
337     }
338
339     @Override
340     protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
341         return helper.add("identifier", getIdentifier().getName());
342     }
343 }