Add OrderedByAwareEffectiveStatement
[yangtools.git] / model / yang-model-spi / src / main / java / org / opendaylight / yangtools / yang / model / spi / meta / AbstractEffectiveStatement.java
index d46dbebbe7fbe42558cffddc00e2b3841f8a549f..71fb8974aeb2a603696e2cc18c6ecb53bb4ad200 100644 (file)
@@ -12,10 +12,12 @@ import static java.util.Objects.requireNonNull;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.common.Empty;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
@@ -23,7 +25,9 @@ import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
 import org.opendaylight.yangtools.yang.model.api.stmt.CaseEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.NamespacedEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
 
 /**
  * Baseline stateless implementation of an EffectiveStatement. This class adds a few default implementations and
@@ -34,13 +38,13 @@ import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStateme
  * This finds immense value in catering the common case, for example effective statements which can, but typically
  * do not, contain substatements.
  *
- * @param <A> Argument type ({@link Void} if statement does not have argument.)
+ * @param <A> Argument type ({@link Empty} if statement does not have argument.)
  * @param <D> Class representing declared version of this statement.
  */
 abstract class AbstractEffectiveStatement<A, D extends DeclaredStatement<A>>
         extends AbstractModelStatement<A> implements EffectiveStatement<A, D> {
     @Override
-    public final <K, V, N extends IdentifierNamespace<K, V>> Optional<? extends V> get(final Class<N> namespace,
+    public final <K, V, N extends IdentifierNamespace<K, V>> Optional<V> get(final Class<N> namespace,
             final K identifier) {
         return Optional.ofNullable(getAll(namespace).get(requireNonNull(identifier)));
     }
@@ -52,7 +56,7 @@ abstract class AbstractEffectiveStatement<A, D extends DeclaredStatement<A>>
     }
 
     @Override
-    public Collection<? extends EffectiveStatement<?, ?>> effectiveSubstatements() {
+    public ImmutableList<? extends EffectiveStatement<?, ?>> effectiveSubstatements() {
         return ImmutableList.of();
     }
 
@@ -83,18 +87,24 @@ abstract class AbstractEffectiveStatement<A, D extends DeclaredStatement<A>>
 
     // TODO: below methods need to find a better place, this is just a temporary hideout as their public class is on
     //       its way out
+    /**
+     * Create a Map containing the contents of the schema tree. Retur
+     * @param substatements Substatements to index
+     * @return Index of the schema tree as a mutable Map
+     * @throws NullPointerException if {@code substatements} is null
+     */
     protected static @NonNull Map<QName, SchemaTreeEffectiveStatement<?>> createSchemaTreeNamespace(
             final Collection<? extends EffectiveStatement<?, ?>> substatements) {
         final Map<QName, SchemaTreeEffectiveStatement<?>> schemaChildren = new LinkedHashMap<>();
         substatements.stream().filter(SchemaTreeEffectiveStatement.class::isInstance)
-            .forEach(child -> putChild(schemaChildren, (SchemaTreeEffectiveStatement<?>) child, "schema"));
+            .forEach(child -> putChild(schemaChildren, (SchemaTreeEffectiveStatement<?>) child, "schema tree"));
         return schemaChildren;
     }
 
-    protected static @NonNull ImmutableMap<QName, DataTreeEffectiveStatement<?>> createDataTreeNamespace(
+    protected static @NonNull Map<QName, DataTreeEffectiveStatement<?>> createDataTreeNamespace(
             final Collection<SchemaTreeEffectiveStatement<?>> schemaTreeStatements,
             // Note: this dance is needed to not retain ImmutableMap$Values
-            final ImmutableMap<QName, SchemaTreeEffectiveStatement<?>> schemaTreeNamespace) {
+            final Map<QName, SchemaTreeEffectiveStatement<?>> schemaTreeNamespace) {
         final Map<QName, DataTreeEffectiveStatement<?>> dataChildren = new LinkedHashMap<>();
         boolean sameAsSchema = true;
 
@@ -106,13 +116,28 @@ abstract class AbstractEffectiveStatement<A, D extends DeclaredStatement<A>>
 
         // This is a mighty hack to lower memory usage: if we consumed all schema tree children as data nodes,
         // the two maps are equal and hence we can share the instance.
-        return sameAsSchema ? (ImmutableMap) schemaTreeNamespace : ImmutableMap.copyOf(dataChildren);
+        return sameAsSchema ? (Map) schemaTreeNamespace : immutableNamespaceOf(dataChildren);
+    }
+
+    protected static <T extends SchemaTreeEffectiveStatement<?>> @NonNull Map<QName, T> immutableNamespaceOf(
+            final Map<QName, T> map) {
+        return map.size() == 1 ? new SingletonNamespace<>(map.values().iterator().next()) : ImmutableMap.copyOf(map);
+    }
+
+    protected static @NonNull HashMap<QName, TypedefEffectiveStatement> createTypedefNamespace(
+            final Collection<? extends EffectiveStatement<?, ?>> substatements) {
+        final HashMap<QName, TypedefEffectiveStatement> typedefs = new HashMap<>();
+
+        substatements.stream().filter(TypedefEffectiveStatement.class::isInstance)
+            .forEach(child -> putChild(typedefs, (TypedefEffectiveStatement) child, "typedef"));
+
+        return typedefs;
     }
 
     private static boolean indexDataTree(final Map<QName, DataTreeEffectiveStatement<?>> map,
             final EffectiveStatement<?, ?> stmt) {
         if (stmt instanceof DataTreeEffectiveStatement) {
-            putChild(map, (DataTreeEffectiveStatement<?>) stmt, "data");
+            putChild(map, (DataTreeEffectiveStatement<?>) stmt, "data tree");
             return true;
         } else if (stmt instanceof ChoiceEffectiveStatement) {
             // For choice statements go through all their cases and fetch their data children
@@ -132,13 +157,13 @@ abstract class AbstractEffectiveStatement<A, D extends DeclaredStatement<A>>
         return false;
     }
 
-    private static <T extends SchemaTreeEffectiveStatement<?>> void putChild(final Map<QName, T> map, final T child,
-            final String tree) {
+    private static <T extends NamespacedEffectiveStatement<?>> void putChild(final Map<QName, T> map, final T child,
+            final String namespace) {
         final QName id = child.getIdentifier();
         final T prev = map.putIfAbsent(id, child);
         if (prev != null) {
             throw new SubstatementIndexingException(
-                "Cannot add " + tree + " tree child with name " + id + ", a conflicting child already exists");
+                "Cannot add " + namespace + " child with name " + id + ", a conflicting child already exists");
         }
     }
 }