BUG-6972: Do not allow root StmtContext to be copied
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / spi / meta / NamespaceBehaviour.java
index 6d156b1c837f2eb75f1001bf1439848309030b59..c24b5c107c4da02ee4f348d0e7f680c1b7e8458d 100644 (file)
@@ -33,7 +33,7 @@ import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
 public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K, V>> implements Identifiable<Class<N>> {
 
     public enum StorageNodeType {
-        GLOBAL, SOURCE_LOCAL_SPECIAL, STATEMENT_LOCAL,
+        GLOBAL, SOURCE_LOCAL_SPECIAL, STATEMENT_LOCAL, ROOT_STATEMENT_LOCAL
     }
 
     public interface Registry {
@@ -41,7 +41,9 @@ public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K,
     }
 
     public interface NamespaceStorageNode {
-
+        /**
+         * @return local namespace behaviour type {@link NamespaceBehaviour}
+         */
         StorageNodeType getStorageNodeType();
 
         @Nullable
@@ -53,14 +55,34 @@ public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K,
         @Nullable
         <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromLocalStorage(Class<N> type);
 
+        /**
+         * Populate specified namespace with a key/value pair, overwriting previous contents. Similar to
+         * {@link Map#put(Object, Object)}.
+         *
+         * @param type Namespace identifier
+         * @param key Key
+         * @param value Value
+         * @return Previously-stored value, or null if the key was not present
+         */
         @Nullable
-        <K, V, N extends IdentifierNamespace<K, V>> void addToLocalStorage(Class<N> type, K key, V value);
-
+        <K, V, N extends IdentifierNamespace<K, V>> V putToLocalStorage(Class<N> type, K key, V value);
+
+        /**
+         * Populate specified namespace with a key/value pair unless the key is already associated with a value. Similar
+         * to {@link Map#putIfAbsent(Object, Object)}.
+         *
+         * @param type Namespace identifier
+         * @param key Key
+         * @param value Value
+         * @return Preexisting value or null if there was no previous mapping
+         */
+        @Nullable
+        <K, V, N extends IdentifierNamespace<K, V>> V putToLocalStorageIfAbsent(Class<N> type, K key, V value);
     }
 
     private final Class<N> identifier;
 
-    protected NamespaceBehaviour(Class<N> identifier) {
+    protected NamespaceBehaviour(final Class<N> identifier) {
         this.identifier = Preconditions.checkNotNull(identifier);
     }
 
@@ -80,7 +102,7 @@ public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K,
      * @return global namespace behaviour for supplied namespace type.
      */
     public static @Nonnull <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> global(
-            Class<N> identifier) {
+            final Class<N> identifier) {
         return new StorageSpecific<>(identifier, StorageNodeType.GLOBAL);
     }
 
@@ -100,12 +122,12 @@ public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K,
      * @return source-local namespace behaviour for supplied namespace type.
      */
     public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> sourceLocal(
-            Class<N> identifier) {
+            final Class<N> identifier) {
         return new StorageSpecific<>(identifier, StorageNodeType.SOURCE_LOCAL_SPECIAL);
     }
 
     public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> statementLocal(
-           Class<N> identifier) {
+           final Class<N> identifier) {
        return new StorageSpecific<>(identifier, StorageNodeType.STATEMENT_LOCAL);
    }
 
@@ -124,7 +146,7 @@ public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K,
      *
      * @return tree-scoped namespace behaviour for supplied namespace type.
      */
-    public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> treeScoped(Class<N> identifier) {
+    public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> treeScoped(final Class<N> identifier) {
         return new TreeScoped<>(identifier);
     }
 
@@ -161,33 +183,30 @@ public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K,
         return identifier;
     }
 
-    protected final V getFromLocalStorage(NamespaceStorageNode storage, K key) {
+    protected final V getFromLocalStorage(final NamespaceStorageNode storage, final K key) {
         return storage.getFromLocalStorage(getIdentifier(), key);
     }
 
-    protected final Map<K, V> getAllFromLocalStorage(NamespaceStorageNode storage) {
+    protected final Map<K, V> getAllFromLocalStorage(final NamespaceStorageNode storage) {
         return storage.getAllFromLocalStorage(getIdentifier());
     }
 
-    protected final void addToStorage(NamespaceStorageNode storage, K key, V value) {
-        storage.addToLocalStorage(getIdentifier(), key, value);
+    protected final void addToStorage(final NamespaceStorageNode storage, final K key, final V value) {
+        storage.putToLocalStorage(getIdentifier(), key, value);
     }
 
     static class StorageSpecific<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
 
         StorageNodeType storageType;
 
-        public StorageSpecific(Class<N> identifier, StorageNodeType type) {
+        public StorageSpecific(final Class<N> identifier, final StorageNodeType type) {
             super(identifier);
             storageType = Preconditions.checkNotNull(type);
         }
 
         @Override
         public V getFrom(final NamespaceStorageNode storage, final K key) {
-            NamespaceStorageNode current = storage;
-            while (current.getStorageNodeType() != storageType) {
-                current = current.getParentNamespaceStorage();
-            }
+            NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
             return getFromLocalStorage(current, key);
         }
 
@@ -202,11 +221,8 @@ public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K,
         }
 
         @Override
-        public void addTo(NamespaceBehaviour.NamespaceStorageNode storage, K key, V value) {
-            NamespaceStorageNode current = storage;
-            while (current.getStorageNodeType() != storageType) {
-                current = current.getParentNamespaceStorage();
-            }
+        public void addTo(final NamespaceBehaviour.NamespaceStorageNode storage, final K key, final V value) {
+            NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
             addToStorage(current, key, value);
         }
 
@@ -214,7 +230,7 @@ public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K,
 
     static class TreeScoped<K, V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
 
-        public TreeScoped(Class<N> identifier) {
+        public TreeScoped(final Class<N> identifier) {
             super(identifier);
         }
 
@@ -245,9 +261,17 @@ public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K,
         }
 
         @Override
-        public void addTo(NamespaceStorageNode storage, K key, V value) {
+        public void addTo(final NamespaceStorageNode storage, final K key, final V value) {
             addToStorage(storage, key, value);
         }
 
     }
+
+    protected static NamespaceStorageNode findClosestTowardsRoot(final NamespaceStorageNode storage, final StorageNodeType type) {
+        NamespaceStorageNode current = storage;
+        while (current != null && current.getStorageNodeType() != type) {
+            current = current.getParentNamespaceStorage();
+        }
+        return current;
+    }
 }