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