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 org.eclipse.jdt.annotation.NonNull;
17 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
18 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceNotAvailableException;
19 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceStorage;
20 import org.opendaylight.yangtools.yang.parser.spi.meta.ParserNamespace;
21 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
25 abstract class AbstractNamespaceStorage implements NamespaceStorage {
26 private static final Logger LOG = LoggerFactory.getLogger(AbstractNamespaceStorage.class);
28 private Map<ParserNamespace<?, ?>, Map<?, ?>> namespaces = ImmutableMap.of();
34 * This method override provides bimorphic invocation on this method invocation between
35 * {@link SourceSpecificContext} and the more general {@link AbstractNamespaceStorage}. We typically do not expect
36 * the two accesses to overlap.
39 public abstract NamespaceStorage getParentStorage();
42 * Get a namespace behavior.
45 * @param <V> value type
46 * @param namespace Namespace type
47 * @return Namespace behaviour
48 * @throws NamespaceNotAvailableException when the namespace is not available
49 * @throws NullPointerException if {@code namespace} is {@code null}
51 abstract <K, V> @NonNull NamespaceBehaviour<K, V> getNamespaceBehaviour(ParserNamespace<K, V> namespace);
53 // FIXME: 8.0.0: do we really need this method?
54 final void checkLocalNamespaceAllowed(final ParserNamespace<?, ?> type) {
55 // Always no-op. We used to route this towards StatementDefinitionContext, but this method remained
56 // unimplemented even there.
60 * Occurs when an item is added to model namespace.
62 * @throws SourceException instance of SourceException
64 <K, V> void onNamespaceElementAdded(final ParserNamespace<K, V> type, final K key, final V value) {
68 final <K, V> Map<K, V> getNamespace(final ParserNamespace<K, V> type) {
69 return getNamespaceBehaviour(type).getAllFrom(this);
72 @SuppressWarnings("unchecked")
73 final <K, V> Map<K, V> getLocalNamespace(final ParserNamespace<K, V> type) {
74 final var local = verifyNotNull(namespaces, "Attempted to access swept namespaces of %s", this);
75 return (Map<K, V>) local.get(type);
78 final <K, V, T extends K, U extends V> void addToNamespace(final ParserNamespace<K, V> type, final T key,
80 getNamespaceBehaviour(type).addTo(this, key, value);
84 public <K, V> V getFromLocalStorage(final ParserNamespace<K, V> type, final K key) {
85 final var localNamespace = getLocalNamespace(type);
86 return localNamespace == null ? null : localNamespace.get(key);
90 public <K, V> Map<K, V> getAllFromLocalStorage(final ParserNamespace<K, V> type) {
91 return getLocalNamespace(type);
95 public <K, V> V putToLocalStorage(final ParserNamespace<K, V> type, final K key, final V value) {
96 final V ret = ensureLocalNamespace(type).put(key, value);
97 onNamespaceElementAdded(type, key, value);
102 public final <K, V> V putToLocalStorageIfAbsent(final ParserNamespace<K, V> type, final K key, final V value) {
103 final V ret = ensureLocalNamespace(type).putIfAbsent(key, value);
105 onNamespaceElementAdded(type, key, value);
110 void sweepNamespaces() {
112 LOG.trace("Swept namespace storages of {}", this);
115 void sweepNamespaces(final Map<ParserNamespace<?, ?>, SweptNamespace> toWipe) {
116 switch (namespaces.size()) {
118 namespaces = ImmutableMap.copyOf(toWipe);
121 namespaces = new HashMap<>(namespaces);
124 // No-op, we are ready
127 namespaces.putAll(toWipe);
128 LOG.trace("Trimmed namespace storages of {} to {}", this, namespaces.keySet());
131 private <K, V> Map<K, V> ensureLocalNamespace(final ParserNamespace<K, V> type) {
132 var ret = getLocalNamespace(type);
134 checkLocalNamespaceAllowed(type);
135 ret = new HashMap<>(1);
137 switch (namespaces.size()) {
139 // We typically have small population of namespaces, use a singleton map
140 namespaces = ImmutableMap.of(type, ret);
143 // Alright, time to grow to a full HashMap
144 final Map<ParserNamespace<?, ?>, Map<?,?>> newNamespaces = new HashMap<>(4);
145 final Entry<ParserNamespace<?, ?>, Map<?, ?>> entry = namespaces.entrySet().iterator().next();
146 newNamespaces.put(entry.getKey(), entry.getValue());
147 namespaces = newNamespaces;
150 // Already expanded, just put the new namespace
151 namespaces.put(type, ret);