2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.parser.stmt.reactor;
10 import static com.google.common.base.Verify.verifyNotNull;
12 import com.google.common.collect.ImmutableMap;
13 import java.util.HashMap;
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;
30 abstract class NamespaceStorageSupport implements NamespaceStorageNode {
31 private static final Logger LOG = LoggerFactory.getLogger(NamespaceStorageSupport.class);
33 private Map<Class<?>, Map<?, ?>> namespaces = ImmutableMap.of();
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.
44 public abstract NamespaceStorageNode getParentNamespaceStorage();
47 * Return the registry of a source context.
49 * @return registry of source context
51 public abstract @NonNull Registry getBehaviourRegistry();
53 protected void checkLocalNamespaceAllowed(final Class<? extends ParserNamespace<?, ?>> type) {
58 * Occurs when an item is added to model namespace.
60 * @throws SourceException instance of SourceException
62 protected <K, V, N extends ParserNamespace<K, V>> void onNamespaceElementAdded(final Class<N> type, final K key,
67 public final <K, V, N extends ParserNamespace<K, V>> Optional<Entry<K, V>> getFromNamespace(
68 final Class<N> type, final NamespaceKeyCriterion<K> criterion) {
69 return getBehaviourRegistry().getNamespaceBehaviour(type).getFrom(this, criterion);
72 public final <K, V, N extends ParserNamespace<K, V>> Map<K, V> getNamespace(final Class<N> type) {
73 return getBehaviourRegistry().getNamespaceBehaviour(type).getAllFrom(this);
76 @SuppressWarnings("unchecked")
77 final <K, V, N extends ParserNamespace<K, V>> Map<K, V> getLocalNamespace(final Class<N> type) {
78 return (Map<K, V>) accessNamespaces().get(type);
81 final <K, V, T extends K, U extends V, N extends ParserNamespace<K, V>> void addToNamespace(
82 final Class<N> type, final T key, final U value) {
83 getBehaviourRegistry().getNamespaceBehaviour(type).addTo(this, key, value);
86 final <K, V, T extends K, U extends V, N extends ParserNamespace<K, V>> void addToNamespace(
87 final Class<N> type, final Map<T, U> map) {
88 final NamespaceBehaviour<K, V, N> behavior = getBehaviourRegistry().getNamespaceBehaviour(type);
89 for (final Entry<T, U> validationBundle : map.entrySet()) {
90 behavior.addTo(this, validationBundle.getKey(), validationBundle.getValue());
95 * Associate a context with a key within a namespace.
97 * @param type Namespace type
99 * @param value Context value
100 * @param <K> namespace key type
101 * @param <N> namespace type
102 * @throws NamespaceNotAvailableException when the namespace is not available.
104 @SuppressWarnings({ "unchecked", "rawtypes" })
105 public final <K, N extends StatementNamespace<K, ?,?>> void addContextToNamespace(final Class<N> type, final K key,
106 final StmtContext<?, ?, ?> value) {
107 getBehaviourRegistry().getNamespaceBehaviour((Class)type).addTo(this, key, value);
110 @SuppressWarnings("unchecked")
112 public <K, V, N extends ParserNamespace<K, V>> V getFromLocalStorage(final Class<N> type, final K key) {
113 final Map<K, V> localNamespace = (Map<K, V>) accessNamespaces().get(type);
114 return localNamespace == null ? null : localNamespace.get(key);
118 public <K, V, N extends ParserNamespace<K, V>> Map<K, V> getAllFromLocalStorage(final Class<N> type) {
119 @SuppressWarnings("unchecked")
120 final Map<K, V> localNamespace = (Map<K, V>) accessNamespaces().get(type);
121 return localNamespace;
125 public <K, V, N extends ParserNamespace<K, V>> V putToLocalStorage(final Class<N> type, final K key,
127 final V ret = ensureLocalNamespace(type).put(key, value);
128 onNamespaceElementAdded(type, key, value);
133 public <K, V, N extends ParserNamespace<K, V>> V putToLocalStorageIfAbsent(final Class<N> type, final K key,
135 final V ret = ensureLocalNamespace(type).putIfAbsent(key, value);
137 onNamespaceElementAdded(type, key, value);
142 void sweepNamespaces() {
144 LOG.trace("Swept namespace storages of {}", this);
147 void sweepNamespaces(final Map<Class<?>, SweptNamespace> toWipe) {
148 switch (namespaces.size()) {
150 namespaces = ImmutableMap.copyOf(toWipe);
153 namespaces = new HashMap<>(namespaces);
156 // No-op, we are ready
159 namespaces.putAll(toWipe);
160 LOG.trace("Trimmed namespace storages of {} to {}", this, namespaces.keySet());
163 private Map<Class<?>, Map<?, ?>> accessNamespaces() {
164 return verifyNotNull(namespaces, "Attempted to access swept namespaces of %s", this);
167 private <K, V, N extends ParserNamespace<K, V>> Map<K, V> ensureLocalNamespace(final Class<N> type) {
168 @SuppressWarnings("unchecked")
169 Map<K, V> ret = (Map<K,V>) accessNamespaces().get(type);
171 checkLocalNamespaceAllowed(type);
172 ret = new HashMap<>(1);
174 switch (namespaces.size()) {
176 // We typically have small population of namespaces, use a singleton map
177 namespaces = ImmutableMap.of(type, ret);
180 // Alright, time to grow to a full HashMap
181 final Map<Class<?>, Map<?,?>> newNamespaces = new HashMap<>(4);
182 final Entry<Class<?>, Map<?, ?>> entry = namespaces.entrySet().iterator().next();
183 newNamespaces.put(entry.getKey(), entry.getValue());
184 namespaces = newNamespaces;
187 // Already expanded, just put the new namespace
188 namespaces.put(type, ret);