Add GroupingNamespace cleaning FIXMEs
[yangtools.git] / yang / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / NamespaceStorageSupport.java
index 26a5ce002ebc46e28f8f14b9fab324c3a6f3f7a6..e6aef831e19f38f9897d321ca5b88109f3436524 100644 (file)
@@ -7,13 +7,16 @@
  */
 package org.opendaylight.yangtools.yang.parser.stmt.reactor;
 
+import static com.google.common.base.Verify.verifyNotNull;
+
 import com.google.common.collect.ImmutableMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Optional;
-import javax.annotation.Nonnull;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode;
 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry;
 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceKeyCriterion;
@@ -21,11 +24,22 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceNotAvailableExce
 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 abstract class NamespaceStorageSupport implements NamespaceStorageNode {
+    private static final Logger LOG = LoggerFactory.getLogger(NamespaceStorageSupport.class);
 
-    private Map<Class<?>, Map<?,?>> namespaces = ImmutableMap.of();
+    private Map<Class<?>, Map<?, ?>> namespaces = ImmutableMap.of();
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p>
+     * This method override provides bimorphic invocation on this method invocation between
+     * {@link SourceSpecificContext} and the more general {@link NamespaceStorageSupport}. We typically do not expect
+     * the two accesses to overlap.
+     */
     @Override
     public abstract NamespaceStorageNode getParentNamespaceStorage();
 
@@ -34,7 +48,7 @@ abstract class NamespaceStorageSupport implements NamespaceStorageNode {
      *
      * @return registry of source context
      */
-    public abstract Registry getBehaviourRegistry();
+    public abstract @NonNull Registry getBehaviourRegistry();
 
     protected void checkLocalNamespaceAllowed(final Class<? extends IdentifierNamespace<?, ?>> type) {
         // NOOP
@@ -50,55 +64,31 @@ abstract class NamespaceStorageSupport implements NamespaceStorageNode {
         // NOOP
     }
 
-    /**
-     * Return a value associated with specified key within a namespace.
-     *
-     * @param type Namespace type
-     * @param key Key
-     * @param <K> namespace key type
-     * @param <V> namespace value type
-     * @param <N> namespace type
-     * @param <T> key type
-     * @return Value, or null if there is no element
-     * @throws NamespaceNotAvailableException when the namespace is not available.
-     */
-    @Nonnull
-    public final <K, V, T extends K, N extends IdentifierNamespace<K, V>> V getFromNamespace(final Class<N> type,
-            final T key) {
-        return getBehaviourRegistry().getNamespaceBehaviour(type).getFrom(this, key);
-    }
-
     public final <K, V, N extends IdentifierNamespace<K, V>> Optional<Entry<K, V>> getFromNamespace(
             final Class<N> type, final NamespaceKeyCriterion<K> criterion) {
         return getBehaviourRegistry().getNamespaceBehaviour(type).getFrom(this, criterion);
     }
 
-    public final <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromNamespace(final Class<N> type) {
+    public final <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getNamespace(final Class<N> type) {
         return getBehaviourRegistry().getNamespaceBehaviour(type).getAllFrom(this);
     }
 
     @SuppressWarnings("unchecked")
-    public final <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromCurrentStmtCtxNamespace(
-            final Class<N> type) {
-        return (Map<K, V>) namespaces.get(type);
+    final <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getLocalNamespace(final Class<N> type) {
+        return (Map<K, V>) accessNamespaces().get(type);
     }
 
-    /**
-     * Associate a value with a key within a namespace.
-     *
-     * @param type Namespace type
-     * @param key Key
-     * @param value value
-     * @param <K> namespace key type
-     * @param <V> namespace value type
-     * @param <N> namespace type
-     * @param <T> key type
-     * @param <U> key type
-     * @throws NamespaceNotAvailableException when the namespace is not available.
-     */
-    public final <K, V, T extends K, U extends V, N extends IdentifierNamespace<K, V>> void addToNs(
+    final <K, V, T extends K, U extends V, N extends IdentifierNamespace<K, V>> void addToNamespace(
             final Class<N> type, final T key, final U value) {
-        getBehaviourRegistry().getNamespaceBehaviour(type).addTo(this,key,value);
+        getBehaviourRegistry().getNamespaceBehaviour(type).addTo(this, key, value);
+    }
+
+    final <K, V, T extends K, U extends V, N extends IdentifierNamespace<K, V>> void addToNamespace(
+            final Class<N> type, final Map<T, U> map) {
+        final NamespaceBehaviour<K, V, N> behavior = getBehaviourRegistry().getNamespaceBehaviour(type);
+        for (final Entry<T, U> validationBundle : map.entrySet()) {
+            behavior.addTo(this, validationBundle.getKey(), validationBundle.getValue());
+        }
     }
 
     /**
@@ -120,33 +110,17 @@ abstract class NamespaceStorageSupport implements NamespaceStorageNode {
     @SuppressWarnings("unchecked")
     @Override
     public <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(final Class<N> type, final K key) {
-        final Map<K, V> localNamespace = (Map<K, V>) namespaces.get(type);
+        final Map<K, V> localNamespace = (Map<K, V>) accessNamespaces().get(type);
         return localNamespace == null ? null : localNamespace.get(key);
     }
 
     @Override
     public <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromLocalStorage(final Class<N> type) {
         @SuppressWarnings("unchecked")
-        final Map<K, V> localNamespace = (Map<K, V>) namespaces.get(type);
+        final Map<K, V> localNamespace = (Map<K, V>) accessNamespaces().get(type);
         return localNamespace;
     }
 
-    private <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> ensureLocalNamespace(final Class<N> type) {
-        @SuppressWarnings("unchecked")
-        Map<K, V> ret = (Map<K,V>) namespaces.get(type);
-        if (ret == null) {
-            checkLocalNamespaceAllowed(type);
-            ret = new HashMap<>(1);
-
-            if (namespaces.isEmpty()) {
-                namespaces = new HashMap<>(1);
-            }
-            namespaces.put(type, ret);
-        }
-
-        return ret;
-    }
-
     @Override
     public <K, V, N extends IdentifierNamespace<K, V>> V putToLocalStorage(final Class<N> type, final K key,
             final V value) {
@@ -164,4 +138,57 @@ abstract class NamespaceStorageSupport implements NamespaceStorageNode {
         }
         return ret;
     }
+
+    void sweepNamespaces() {
+        namespaces = null;
+        LOG.trace("Swept namespace storages of {}", this);
+    }
+
+    void sweepNamespaces(final Map<Class<?>, SweptNamespace> toWipe) {
+        switch (namespaces.size()) {
+            case 0:
+                namespaces = ImmutableMap.copyOf(toWipe);
+                return;
+            case 1:
+                namespaces = new HashMap<>(namespaces);
+                break;
+            default:
+                // No-op, we are ready
+        }
+
+        namespaces.putAll(toWipe);
+        LOG.trace("Trimmed namespace storages of {} to {}", this, namespaces.keySet());
+    }
+
+    private Map<Class<?>, Map<?, ?>> accessNamespaces() {
+        return verifyNotNull(namespaces, "Attempted to access swept namespaces of %s", this);
+    }
+
+    private <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> ensureLocalNamespace(final Class<N> type) {
+        @SuppressWarnings("unchecked")
+        Map<K, V> ret = (Map<K,V>) accessNamespaces().get(type);
+        if (ret == null) {
+            checkLocalNamespaceAllowed(type);
+            ret = new HashMap<>(1);
+
+            switch (namespaces.size()) {
+                case 0:
+                    // We typically have small population of namespaces, use a singleton map
+                    namespaces = ImmutableMap.of(type, ret);
+                    break;
+                case 1:
+                    // Alright, time to grow to a full HashMap
+                    final Map<Class<?>, Map<?,?>> newNamespaces = new HashMap<>(4);
+                    final Entry<Class<?>, Map<?, ?>> entry = namespaces.entrySet().iterator().next();
+                    newNamespaces.put(entry.getKey(), entry.getValue());
+                    namespaces = newNamespaces;
+                    // fall through
+                default:
+                    // Already expanded, just put the new namespace
+                    namespaces.put(type, ret);
+            }
+        }
+
+        return ret;
+    }
 }