Remove ReactorStmtCtx.checkLocalNamespaceAllowed()
[yangtools.git] / yang / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / NamespaceStorageSupport.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.stmt.reactor;
9
10 import static com.google.common.base.Verify.verifyNotNull;
11
12 import com.google.common.collect.ImmutableMap;
13 import java.util.HashMap;
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.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
19 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode;
20 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry;
21 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceKeyCriterion;
22 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceNotAvailableException;
23 import org.opendaylight.yangtools.yang.parser.spi.meta.ParserNamespace;
24 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
25 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
26 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 abstract class NamespaceStorageSupport implements NamespaceStorageNode {
31     private static final Logger LOG = LoggerFactory.getLogger(NamespaceStorageSupport.class);
32
33     private Map<Class<?>, Map<?, ?>> namespaces = ImmutableMap.of();
34
35     /**
36      * {@inheritDoc}
37      *
38      * <p>
39      * This method override provides bimorphic invocation on this method invocation between
40      * {@link SourceSpecificContext} and the more general {@link NamespaceStorageSupport}. We typically do not expect
41      * the two accesses to overlap.
42      */
43     @Override
44     public abstract NamespaceStorageNode getParentNamespaceStorage();
45
46     /**
47      * Return the registry of a source context.
48      *
49      * @return registry of source context
50      */
51     public abstract @NonNull Registry getBehaviourRegistry();
52
53     // FIXME: 8.0.0: do we really need this method?
54     final void checkLocalNamespaceAllowed(final Class<? extends ParserNamespace<?, ?>> type) {
55         // Always no-op. We used to route this towards StatementDefinitionContext, but this method remained
56         // unimplemented even there.
57     }
58
59     /**
60      * Occurs when an item is added to model namespace.
61      *
62      * @throws SourceException instance of SourceException
63      */
64     protected <K, V, N extends ParserNamespace<K, V>> void onNamespaceElementAdded(final Class<N> type, final K key,
65             final V value) {
66         // NOOP
67     }
68
69     public final <K, V, N extends ParserNamespace<K, V>> Optional<Entry<K, V>> getFromNamespace(
70             final Class<N> type, final NamespaceKeyCriterion<K> criterion) {
71         return getBehaviourRegistry().getNamespaceBehaviour(type).getFrom(this, criterion);
72     }
73
74     public final <K, V, N extends ParserNamespace<K, V>> Map<K, V> getNamespace(final Class<N> type) {
75         return getBehaviourRegistry().getNamespaceBehaviour(type).getAllFrom(this);
76     }
77
78     @SuppressWarnings("unchecked")
79     final <K, V, N extends ParserNamespace<K, V>> Map<K, V> getLocalNamespace(final Class<N> type) {
80         return (Map<K, V>) accessNamespaces().get(type);
81     }
82
83     final <K, V, T extends K, U extends V, N extends ParserNamespace<K, V>> void addToNamespace(
84             final Class<N> type, final T key, final U value) {
85         getBehaviourRegistry().getNamespaceBehaviour(type).addTo(this, key, value);
86     }
87
88     final <K, V, T extends K, U extends V, N extends ParserNamespace<K, V>> void addToNamespace(
89             final Class<N> type, final Map<T, U> map) {
90         final NamespaceBehaviour<K, V, N> behavior = getBehaviourRegistry().getNamespaceBehaviour(type);
91         for (final Entry<T, U> validationBundle : map.entrySet()) {
92             behavior.addTo(this, validationBundle.getKey(), validationBundle.getValue());
93         }
94     }
95
96     /**
97      * Associate a context with a key within a namespace.
98      *
99      * @param type Namespace type
100      * @param key Key
101      * @param value Context value
102      * @param <K> namespace key type
103      * @param <N> namespace type
104      * @throws NamespaceNotAvailableException when the namespace is not available.
105      */
106     @SuppressWarnings({ "unchecked", "rawtypes" })
107     public final <K, N extends StatementNamespace<K, ?,?>> void addContextToNamespace(final Class<N> type, final K key,
108             final StmtContext<?, ?, ?> value) {
109         getBehaviourRegistry().getNamespaceBehaviour((Class)type).addTo(this, key, value);
110     }
111
112     @SuppressWarnings("unchecked")
113     @Override
114     public <K, V, N extends ParserNamespace<K, V>> V getFromLocalStorage(final Class<N> type, final K key) {
115         final Map<K, V> localNamespace = (Map<K, V>) accessNamespaces().get(type);
116         return localNamespace == null ? null : localNamespace.get(key);
117     }
118
119     @Override
120     public <K, V, N extends ParserNamespace<K, V>> Map<K, V> getAllFromLocalStorage(final Class<N> type) {
121         @SuppressWarnings("unchecked")
122         final Map<K, V> localNamespace = (Map<K, V>) accessNamespaces().get(type);
123         return localNamespace;
124     }
125
126     @Override
127     public <K, V, N extends ParserNamespace<K, V>> V putToLocalStorage(final Class<N> type, final K key,
128             final V value) {
129         final V ret = ensureLocalNamespace(type).put(key, value);
130         onNamespaceElementAdded(type, key, value);
131         return ret;
132     }
133
134     @Override
135     public <K, V, N extends ParserNamespace<K, V>> V putToLocalStorageIfAbsent(final Class<N> type, final K key,
136             final V value) {
137         final V ret = ensureLocalNamespace(type).putIfAbsent(key, value);
138         if (ret == null) {
139             onNamespaceElementAdded(type, key, value);
140         }
141         return ret;
142     }
143
144     void sweepNamespaces() {
145         namespaces = null;
146         LOG.trace("Swept namespace storages of {}", this);
147     }
148
149     void sweepNamespaces(final Map<Class<?>, SweptNamespace> toWipe) {
150         switch (namespaces.size()) {
151             case 0:
152                 namespaces = ImmutableMap.copyOf(toWipe);
153                 return;
154             case 1:
155                 namespaces = new HashMap<>(namespaces);
156                 break;
157             default:
158                 // No-op, we are ready
159         }
160
161         namespaces.putAll(toWipe);
162         LOG.trace("Trimmed namespace storages of {} to {}", this, namespaces.keySet());
163     }
164
165     private Map<Class<?>, Map<?, ?>> accessNamespaces() {
166         return verifyNotNull(namespaces, "Attempted to access swept namespaces of %s", this);
167     }
168
169     private <K, V, N extends ParserNamespace<K, V>> Map<K, V> ensureLocalNamespace(final Class<N> type) {
170         @SuppressWarnings("unchecked")
171         Map<K, V> ret = (Map<K,V>) accessNamespaces().get(type);
172         if (ret == null) {
173             checkLocalNamespaceAllowed(type);
174             ret = new HashMap<>(1);
175
176             switch (namespaces.size()) {
177                 case 0:
178                     // We typically have small population of namespaces, use a singleton map
179                     namespaces = ImmutableMap.of(type, ret);
180                     break;
181                 case 1:
182                     // Alright, time to grow to a full HashMap
183                     final Map<Class<?>, Map<?,?>> newNamespaces = new HashMap<>(4);
184                     final Entry<Class<?>, Map<?, ?>> entry = namespaces.entrySet().iterator().next();
185                     newNamespaces.put(entry.getKey(), entry.getValue());
186                     namespaces = newNamespaces;
187                     // fall through
188                 default:
189                     // Already expanded, just put the new namespace
190                     namespaces.put(type, ret);
191             }
192         }
193
194         return ret;
195     }
196 }