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 0f795cc1710c81df39b79c44458d0a0ec8c2b92e..c24b5c107c4da02ee4f348d0e7f680c1b7e8458d 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.yangtools.yang.parser.spi.meta;
 
 import com.google.common.base.Preconditions;
+import java.util.Map;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import org.opendaylight.yangtools.concepts.Identifiable;
@@ -16,46 +17,72 @@ import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
 /**
  * Definition / implementation of specific Identifier Namespace behaviour.
  *
- * Namespace behaviour is build on top of tree of {@link NamespaceStorageNode}
- * which represents local context of one of types defined in {@link StorageNodeType}.
+ * Namespace behaviour is build on top of tree of {@link NamespaceStorageNode} which represents local context of one of
+ * types defined in {@link StorageNodeType}.
  *
- * For common behaviour models please use static factories {@link #global(Class)},
- * {@link #sourceLocal(Class)} and {@link #treeScoped(Class)}.
+ * For common behaviour models please use static factories {@link #global(Class)}, {@link #sourceLocal(Class)} and
+ * {@link #treeScoped(Class)}.
  *
- * @param <K> Key type
- * @param <V> Value type
- * @param <N> Namespace Type
+ * @param <K>
+ *            Key type
+ * @param <V>
+ *            Value type
+ * @param <N>
+ *            Namespace Type
  */
-public abstract class NamespaceBehaviour<K,V, N extends IdentifierNamespace<K, V>> implements Identifiable<Class<N>>{
+public abstract class NamespaceBehaviour<K, V, N extends IdentifierNamespace<K, V>> implements Identifiable<Class<N>> {
 
     public enum StorageNodeType {
-        Global,
-        SourceLocalSpecial,
-        StatementLocal
+        GLOBAL, SOURCE_LOCAL_SPECIAL, STATEMENT_LOCAL, ROOT_STATEMENT_LOCAL
     }
 
     public interface Registry {
-
-        abstract <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(Class<N> type);
-
+        <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(Class<N> type);
     }
 
     public interface NamespaceStorageNode {
-
+        /**
+         * @return local namespace behaviour type {@link NamespaceBehaviour}
+         */
         StorageNodeType getStorageNodeType();
 
-        @Nullable NamespaceStorageNode getParentNamespaceStorage();
-
-        @Nullable  <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(Class<N> type, K key);
-
-        @Nullable  <K, V, N extends IdentifierNamespace<K, V>> void addToLocalStorage(Class<N> type, K key, V value);
-
+        @Nullable
+        NamespaceStorageNode getParentNamespaceStorage();
+
+        @Nullable
+        <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(Class<N> type, K key);
+
+        @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>> 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);
     }
 
@@ -63,103 +90,156 @@ public abstract class NamespaceBehaviour<K,V, N extends IdentifierNamespace<K, V
      *
      * Creates global namespace behaviour for supplied namespace type.
      *
-     * Global behaviour stores and loads all values from root {@link NamespaceStorageNode}
-     * with type of {@link StorageNodeType#Global}.
+     * Global behaviour stores and loads all values from root {@link NamespaceStorageNode} with type of
+     * {@link StorageNodeType#GLOBAL}.
+     *
+     * @param identifier
+     *            Namespace identifier.
+     * @param <K> type parameter
+     * @param <V> type parameter
+     * @param <N> type parameter
      *
-     * @param identifier Namespace identifier.
      * @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) {
-        return new StorageSpecific<>(identifier, StorageNodeType.Global);
+    public static @Nonnull <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> global(
+            final Class<N> identifier) {
+        return new StorageSpecific<>(identifier, StorageNodeType.GLOBAL);
     }
 
     /**
      *
      * Creates source-local namespace behaviour for supplied namespace type.
      *
-     * Source-local namespace behaviour stores and loads all values from closest
-     * {@link NamespaceStorageNode} ancestor with type of
-     * {@link StorageNodeType#SourceLocalSpecial}.
+     * Source-local namespace behaviour stores and loads all values from closest {@link NamespaceStorageNode} ancestor
+     * with type of {@link StorageNodeType#SOURCE_LOCAL_SPECIAL}.
+     *
+     * @param identifier
+     *            Namespace identifier.
+     * @param <K> type parameter
+     * @param <V> type parameter
+     * @param <N> type parameter
      *
-     * @param identifier Namespace identifier.
      * @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) {
-        return new StorageSpecific<>(identifier, StorageNodeType.SourceLocalSpecial);
+    public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> sourceLocal(
+            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(
+           final Class<N> identifier) {
+       return new StorageSpecific<>(identifier, StorageNodeType.STATEMENT_LOCAL);
+   }
+
     /**
-    *
-    * Creates tree-scoped namespace behaviour for supplied namespace type.
-    *
-    * Tree-scoped namespace behaviour search for value in all storage nodes
-    * up to the root and stores values in supplied node.
-    *
-    * @param identifier Namespace identifier.
-    * @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) {
+     *
+     * Creates tree-scoped namespace behaviour for supplied namespace type.
+     *
+     * Tree-scoped namespace behaviour search for value in all storage nodes up to the root and stores values in
+     * supplied node.
+     *
+     * @param identifier
+     *            Namespace identifier.     *
+     * @param <K> type parameter
+     * @param <V> type parameter
+     * @param <N> type parameter
+     *
+     * @return tree-scoped namespace behaviour for supplied namespace type.
+     */
+    public static <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> treeScoped(final Class<N> identifier) {
         return new TreeScoped<>(identifier);
     }
 
+    /**
+     * returns value from model namespace storage according to key param class
+     *
+     * @param storage namespace storage
+     * @param key type parameter
+     *
+     * @return value from model namespace storage according to key param class
+     */
     public abstract V getFrom(NamespaceStorageNode storage, K key);
-    public abstract void addTo(NamespaceStorageNode storage,K key,V value);
 
+    /**
+     * returns all values of a keys of param class from model namespace storage
+     *
+     * @param storage namespace storage
+     *
+     * @return all values of keys of param class from model namespace storage
+     */
+    public abstract Map<K, V> getAllFrom(NamespaceStorageNode storage);
+
+    /**
+     * adds key and value to corresponding namespace storage according to param class
+     *
+     * @param storage namespace storage
+     * @param key type parameter
+     * @param value type parameter
+     */
+    public abstract void addTo(NamespaceStorageNode storage, K key, V value);
 
     @Override
     public Class<N> getIdentifier() {
         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 void addToStorage(NamespaceStorageNode storage,K key,V value) {
-        storage.addToLocalStorage(getIdentifier(),key,value);
+    protected final Map<K, V> getAllFromLocalStorage(final NamespaceStorageNode storage) {
+        return storage.getAllFromLocalStorage(getIdentifier());
     }
 
-    static class StorageSpecific<K,V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
+    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.getParentNamespaceStorage() != null) {
-                current = current.getParentNamespaceStorage();
-            }
-            return getFromLocalStorage(current,key);
+            NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
+            return getFromLocalStorage(current, key);
         }
 
         @Override
-        public void addTo(NamespaceBehaviour.NamespaceStorageNode storage, K key, V value) {
+        public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
             NamespaceStorageNode current = storage;
-            while(current.getStorageNodeType() != storageType) {
+            while (current.getStorageNodeType() != storageType) {
                 current = current.getParentNamespaceStorage();
             }
+
+            return getAllFromLocalStorage(current);
+        }
+
+        @Override
+        public void addTo(final NamespaceBehaviour.NamespaceStorageNode storage, final K key, final V value) {
+            NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType);
             addToStorage(current, key, value);
         }
 
     }
 
-    static class TreeScoped<K,V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
+    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);
         }
 
         @Override
         public V getFrom(final NamespaceStorageNode storage, final K key) {
             NamespaceStorageNode current = storage;
-            while(current != null) {
+            while (current != null) {
                 final V val = getFromLocalStorage(current, key);
-                if(val != null) {
+                if (val != null) {
                     return val;
                 }
                 current = current.getParentNamespaceStorage();
@@ -168,10 +248,30 @@ public abstract class NamespaceBehaviour<K,V, N extends IdentifierNamespace<K, V
         }
 
         @Override
-        public void addTo(NamespaceStorageNode storage,K key, V value) {
+        public Map<K, V> getAllFrom(final NamespaceStorageNode storage) {
+            NamespaceStorageNode current = storage;
+            while (current != null) {
+                final Map<K, V> val = getAllFromLocalStorage(current);
+                if (val != null) {
+                    return val;
+                }
+                current = current.getParentNamespaceStorage();
+            }
+            return null;
+        }
+
+        @Override
+        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;
+    }
 }