c24b5c107c4da02ee4f348d0e7f680c1b7e8458d
[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 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          * @return local namespace behaviour type {@link NamespaceBehaviour}
46          */
47         StorageNodeType getStorageNodeType();
48
49         @Nullable
50         NamespaceStorageNode getParentNamespaceStorage();
51
52         @Nullable
53         <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(Class<N> type, K key);
54
55         @Nullable
56         <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromLocalStorage(Class<N> type);
57
58         /**
59          * Populate specified namespace with a key/value pair, overwriting previous contents. Similar to
60          * {@link Map#put(Object, Object)}.
61          *
62          * @param type Namespace identifier
63          * @param key Key
64          * @param value Value
65          * @return Previously-stored value, or null if the key was not present
66          */
67         @Nullable
68         <K, V, N extends IdentifierNamespace<K, V>> V putToLocalStorage(Class<N> type, K key, V value);
69
70         /**
71          * Populate specified namespace with a key/value pair unless the key is already associated with a value. Similar
72          * to {@link Map#putIfAbsent(Object, Object)}.
73          *
74          * @param type Namespace identifier
75          * @param key Key
76          * @param value Value
77          * @return Preexisting value or null if there was no previous mapping
78          */
79         @Nullable
80         <K, V, N extends IdentifierNamespace<K, V>> V putToLocalStorageIfAbsent(Class<N> type, K key, V value);
81     }
82
83     private final Class<N> identifier;
84
85     protected NamespaceBehaviour(final Class<N> identifier) {
86         this.identifier = Preconditions.checkNotNull(identifier);
87     }
88
89     /**
90      *
91      * Creates global namespace behaviour for supplied namespace type.
92      *
93      * Global behaviour stores and loads all values from root {@link NamespaceStorageNode} with type of
94      * {@link StorageNodeType#GLOBAL}.
95      *
96      * @param identifier
97      *            Namespace identifier.
98      * @param <K> type parameter
99      * @param <V> type parameter
100      * @param <N> type parameter
101      *
102      * @return global namespace behaviour for supplied namespace type.
103      */
104     public static @Nonnull <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> global(
105             final Class<N> identifier) {
106         return new StorageSpecific<>(identifier, StorageNodeType.GLOBAL);
107     }
108
109     /**
110      *
111      * Creates source-local namespace behaviour for supplied namespace type.
112      *
113      * Source-local namespace behaviour stores and loads all values from closest {@link NamespaceStorageNode} ancestor
114      * with type of {@link StorageNodeType#SOURCE_LOCAL_SPECIAL}.
115      *
116      * @param identifier
117      *            Namespace identifier.
118      * @param <K> type parameter
119      * @param <V> type parameter
120      * @param <N> type parameter
121      *
122      * @return source-local namespace behaviour for supplied namespace type.
123      */
124     public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> sourceLocal(
125             final Class<N> identifier) {
126         return new StorageSpecific<>(identifier, StorageNodeType.SOURCE_LOCAL_SPECIAL);
127     }
128
129     public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> statementLocal(
130            final Class<N> identifier) {
131        return new StorageSpecific<>(identifier, StorageNodeType.STATEMENT_LOCAL);
132    }
133
134     /**
135      *
136      * Creates tree-scoped namespace behaviour for supplied namespace type.
137      *
138      * Tree-scoped namespace behaviour search for value in all storage nodes up to the root and stores values in
139      * supplied node.
140      *
141      * @param identifier
142      *            Namespace identifier.     *
143      * @param <K> type parameter
144      * @param <V> type parameter
145      * @param <N> type parameter
146      *
147      * @return tree-scoped namespace behaviour for supplied namespace type.
148      */
149     public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> treeScoped(final Class<N> identifier) {
150         return new TreeScoped<>(identifier);
151     }
152
153     /**
154      * returns value from model namespace storage according to key param class
155      *
156      * @param storage namespace storage
157      * @param key type parameter
158      *
159      * @return value from model namespace storage according to key param class
160      */
161     public abstract V getFrom(NamespaceStorageNode storage, K key);
162
163     /**
164      * returns all values of a keys of param class from model namespace storage
165      *
166      * @param storage namespace storage
167      *
168      * @return all values of keys of param class from model namespace storage
169      */
170     public abstract Map<K, V> getAllFrom(NamespaceStorageNode storage);
171
172     /**
173      * adds key and value to corresponding namespace storage according to param class
174      *
175      * @param storage namespace storage
176      * @param key type parameter
177      * @param value type parameter
178      */
179     public abstract void addTo(NamespaceStorageNode storage, K key, V value);
180
181     @Override
182     public Class<N> getIdentifier() {
183         return identifier;
184     }
185
186     protected final V getFromLocalStorage(final NamespaceStorageNode storage, final K key) {
187         return storage.getFromLocalStorage(getIdentifier(), key);
188     }
189
190     protected final Map<K, V> getAllFromLocalStorage(final NamespaceStorageNode storage) {
191         return storage.getAllFromLocalStorage(getIdentifier());
192     }
193
194     protected final void addToStorage(final NamespaceStorageNode storage, final K key, final V value) {
195         storage.putToLocalStorage(getIdentifier(), key, value);
196     }
197
198     static class StorageSpecific<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
199
200         StorageNodeType storageType;
201
202         public StorageSpecific(final Class<N> identifier, final StorageNodeType type) {
203             super(identifier);
204             storageType = Preconditions.checkNotNull(type);
205         }
206
207         @Override
208         public V getFrom(final NamespaceStorageNode storage, final K key) {
209             NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
210             return getFromLocalStorage(current, key);
211         }
212
213         @Override
214         public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
215             NamespaceStorageNode current = storage;
216             while (current.getStorageNodeType() != storageType) {
217                 current = current.getParentNamespaceStorage();
218             }
219
220             return getAllFromLocalStorage(current);
221         }
222
223         @Override
224         public void addTo(final NamespaceBehaviour.NamespaceStorageNode storage, final K key, final V value) {
225             NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
226             addToStorage(current, key, value);
227         }
228
229     }
230
231     static class TreeScoped<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
232
233         public TreeScoped(final Class<N> identifier) {
234             super(identifier);
235         }
236
237         @Override
238         public V getFrom(final NamespaceStorageNode storage, final K key) {
239             NamespaceStorageNode current = storage;
240             while (current != null) {
241                 final V val = getFromLocalStorage(current, key);
242                 if (val != null) {
243                     return val;
244                 }
245                 current = current.getParentNamespaceStorage();
246             }
247             return null;
248         }
249
250         @Override
251         public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
252             NamespaceStorageNode current = storage;
253             while (current != null) {
254                 final Map<K, V> val = getAllFromLocalStorage(current);
255                 if (val != null) {
256                     return val;
257                 }
258                 current = current.getParentNamespaceStorage();
259             }
260             return null;
261         }
262
263         @Override
264         public void addTo(final NamespaceStorageNode storage, final K key, final V value) {
265             addToStorage(storage, key, value);
266         }
267
268     }
269
270     protected static NamespaceStorageNode findClosestTowardsRoot(final NamespaceStorageNode storage, final StorageNodeType type) {
271         NamespaceStorageNode current = storage;
272         while (current != null && current.getStorageNodeType() != type) {
273             current = current.getParentNamespaceStorage();
274         }
275         return current;
276     }
277 }