Bug 5899: Cardinality check incorrectly limited to 1 for "must"
[yangtools.git] / yang / yang-parser-impl / 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 com.google.common.base.Preconditions;
11 import java.util.Map;
12 import javax.annotation.Nonnull;
13 import javax.annotation.Nullable;
14 import org.opendaylight.yangtools.concepts.Identifiable;
15 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
16
17 /**
18  * Definition / implementation of specific Identifier Namespace behaviour.
19  *
20  * Namespace behaviour is build on top of tree of {@link NamespaceStorageNode} which represents local context of one of
21  * types defined in {@link StorageNodeType}.
22  *
23  * For common behaviour models please use static factories {@link #global(Class)}, {@link #sourceLocal(Class)} and
24  * {@link #treeScoped(Class)}.
25  *
26  * @param <K>
27  *            Key type
28  * @param <V>
29  *            Value type
30  * @param <N>
31  *            Namespace Type
32  */
33 public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K, V>> implements Identifiable<Class<N>> {
34
35     public enum StorageNodeType {
36         GLOBAL, SOURCE_LOCAL_SPECIAL, STATEMENT_LOCAL, ROOT_STATEMENT_LOCAL
37     }
38
39     public interface Registry {
40         <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(Class<N> type);
41     }
42
43     public interface NamespaceStorageNode {
44
45         StorageNodeType getStorageNodeType();
46
47         @Nullable
48         NamespaceStorageNode getParentNamespaceStorage();
49
50         @Nullable
51         <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(Class<N> type, K key);
52
53         @Nullable
54         <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromLocalStorage(Class<N> type);
55
56         @Nullable
57         <K, V, N extends IdentifierNamespace<K, V>> void addToLocalStorage(Class<N> type, K key, V value);
58
59     }
60
61     private final Class<N> identifier;
62
63     protected NamespaceBehaviour(Class<N> identifier) {
64         this.identifier = Preconditions.checkNotNull(identifier);
65     }
66
67     /**
68      *
69      * Creates global namespace behaviour for supplied namespace type.
70      *
71      * Global behaviour stores and loads all values from root {@link NamespaceStorageNode} with type of
72      * {@link StorageNodeType#GLOBAL}.
73      *
74      * @param identifier
75      *            Namespace identifier.
76      * @param <K> type parameter
77      * @param <V> type parameter
78      * @param <N> type parameter
79      *
80      * @return global namespace behaviour for supplied namespace type.
81      */
82     public static @Nonnull <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> global(
83             Class<N> identifier) {
84         return new StorageSpecific<>(identifier, StorageNodeType.GLOBAL);
85     }
86
87     /**
88      *
89      * Creates source-local namespace behaviour for supplied namespace type.
90      *
91      * Source-local namespace behaviour stores and loads all values from closest {@link NamespaceStorageNode} ancestor
92      * with type of {@link StorageNodeType#SOURCE_LOCAL_SPECIAL}.
93      *
94      * @param identifier
95      *            Namespace identifier.
96      * @param <K> type parameter
97      * @param <V> type parameter
98      * @param <N> type parameter
99      *
100      * @return source-local namespace behaviour for supplied namespace type.
101      */
102     public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> sourceLocal(
103             Class<N> identifier) {
104         return new StorageSpecific<>(identifier, StorageNodeType.SOURCE_LOCAL_SPECIAL);
105     }
106
107     public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> statementLocal(
108            Class<N> identifier) {
109        return new StorageSpecific<>(identifier, StorageNodeType.STATEMENT_LOCAL);
110    }
111
112     /**
113      *
114      * Creates tree-scoped namespace behaviour for supplied namespace type.
115      *
116      * Tree-scoped namespace behaviour search for value in all storage nodes up to the root and stores values in
117      * supplied node.
118      *
119      * @param identifier
120      *            Namespace identifier.     *
121      * @param <K> type parameter
122      * @param <V> type parameter
123      * @param <N> type parameter
124      *
125      * @return tree-scoped namespace behaviour for supplied namespace type.
126      */
127     public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> treeScoped(Class<N> identifier) {
128         return new TreeScoped<>(identifier);
129     }
130
131     /**
132      * returns value from model namespace storage according to key param class
133      *
134      * @param storage namespace storage
135      * @param key type parameter
136      *
137      * @return value from model namespace storage according to key param class
138      */
139     public abstract V getFrom(NamespaceStorageNode storage, K key);
140
141     /**
142      * returns all values of a keys of param class from model namespace storage
143      *
144      * @param storage namespace storage
145      *
146      * @return all values of keys of param class from model namespace storage
147      */
148     public abstract Map<K, V> getAllFrom(NamespaceStorageNode storage);
149
150     /**
151      * adds key and value to corresponding namespace storage according to param class
152      *
153      * @param storage namespace storage
154      * @param key type parameter
155      * @param value type parameter
156      */
157     public abstract void addTo(NamespaceStorageNode storage, K key, V value);
158
159     @Override
160     public Class<N> getIdentifier() {
161         return identifier;
162     }
163
164     protected final V getFromLocalStorage(NamespaceStorageNode storage, K key) {
165         return storage.getFromLocalStorage(getIdentifier(), key);
166     }
167
168     protected final Map<K, V> getAllFromLocalStorage(NamespaceStorageNode storage) {
169         return storage.getAllFromLocalStorage(getIdentifier());
170     }
171
172     protected final void addToStorage(NamespaceStorageNode storage, K key, V value) {
173         storage.addToLocalStorage(getIdentifier(), key, value);
174     }
175
176     static class StorageSpecific<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
177
178         StorageNodeType storageType;
179
180         public StorageSpecific(Class<N> identifier, StorageNodeType type) {
181             super(identifier);
182             storageType = Preconditions.checkNotNull(type);
183         }
184
185         @Override
186         public V getFrom(final NamespaceStorageNode storage, final K key) {
187             NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
188             return getFromLocalStorage(current, key);
189         }
190
191         @Override
192         public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
193             NamespaceStorageNode current = storage;
194             while (current.getStorageNodeType() != storageType) {
195                 current = current.getParentNamespaceStorage();
196             }
197
198             return getAllFromLocalStorage(current);
199         }
200
201         @Override
202         public void addTo(NamespaceBehaviour.NamespaceStorageNode storage, K key, V value) {
203             NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
204             addToStorage(current, key, value);
205         }
206
207     }
208
209     static class TreeScoped<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
210
211         public TreeScoped(Class<N> identifier) {
212             super(identifier);
213         }
214
215         @Override
216         public V getFrom(final NamespaceStorageNode storage, final K key) {
217             NamespaceStorageNode current = storage;
218             while (current != null) {
219                 final V val = getFromLocalStorage(current, key);
220                 if (val != null) {
221                     return val;
222                 }
223                 current = current.getParentNamespaceStorage();
224             }
225             return null;
226         }
227
228         @Override
229         public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
230             NamespaceStorageNode current = storage;
231             while (current != null) {
232                 final Map<K, V> val = getAllFromLocalStorage(current);
233                 if (val != null) {
234                     return val;
235                 }
236                 current = current.getParentNamespaceStorage();
237             }
238             return null;
239         }
240
241         @Override
242         public void addTo(NamespaceStorageNode storage, K key, V value) {
243             addToStorage(storage, key, value);
244         }
245
246     }
247
248     protected static NamespaceStorageNode findClosestTowardsRoot(NamespaceStorageNode storage, StorageNodeType type) {
249         NamespaceStorageNode current = storage;
250         while(current != null && current.getStorageNodeType() != type) {
251             current = current.getParentNamespaceStorage();
252         }
253         return current;
254     }
255 }