Refactor grouping statement implementations 85/87485/1
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 4 Feb 2020 23:37:58 +0000 (00:37 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Thu, 6 Feb 2020 11:27:39 +0000 (12:27 +0100)
Groupings have large footprint, make sure we minimize it. As we do not
want to make GroupingEffectiveStatement SchemaTreeAware just yet, we
create a lazily-instantiated DefaultDataNodeContainer class to support
DataNodeContainer aspects.

JIRA: YANGTOOLS-1065
Change-Id: Ia1183c2d7f83599462724b35e2f3aad4f160eef1
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/GroupingEffectiveStatement.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/GroupingStatement.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/AbstractDeclaredEffectiveStatement.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/grouping/AbstractGroupingStatementSupport.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/grouping/EmptyGroupingStatement.java [moved from yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/grouping/GroupingStatementImpl.java with 57% similarity]
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/grouping/GroupingEffectiveStatementImpl.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/grouping/RegularGroupingStatement.java [new file with mode: 0644]

index d9b0c527b8eba9e672499a50bbe3a7125a89b888..8c644e296aa378410674a153fc57f17f9fdd1a97 100644 (file)
@@ -9,9 +9,14 @@ package org.opendaylight.yangtools.yang.model.api.stmt;
 
 import com.google.common.annotations.Beta;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
 
 @Beta
 public interface GroupingEffectiveStatement extends EffectiveStatement<QName, GroupingStatement> {
-
+    @Override
+    default StatementDefinition statementDefinition() {
+        return YangStmtMapping.GROUPING;
+    }
 }
index 32328745279ce1c12c695b494e32507114334b13..4bde14c318bdb250a6cb428f74fe10ee8051c367 100644 (file)
@@ -11,10 +11,17 @@ import static com.google.common.base.Verify.verifyNotNull;
 
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
 
 public interface GroupingStatement extends DocumentedDeclaredStatement.WithStatus<QName>,
         DataDefinitionAwareDeclaredStatement.WithReusableDefinitions<QName>,
         NotificationStatementAwareDeclaredStatement<QName>, ActionStatementAwareDeclaredStatement<QName> {
+    @Override
+    default StatementDefinition statementDefinition() {
+        return YangStmtMapping.GROUPING;
+    }
+
     default @NonNull QName getName() {
         // FIXME: YANGTOOLS-908: verifyNotNull() should not be needed here
         return verifyNotNull(argument());
index 02f12e609bf20cdeb2805b6d04100f265e2ee84c..d762c1442926566cc2d65ef8ab22ee44259f2336 100644 (file)
@@ -13,6 +13,7 @@ import static java.util.Objects.requireNonNull;
 import com.google.common.annotations.Beta;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
@@ -28,7 +29,9 @@ import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeAwareEffectiveStat
 import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.DataNodeContainerMixin;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
 
 /**
@@ -131,6 +134,46 @@ public abstract class AbstractDeclaredEffectiveStatement<A, D extends DeclaredSt
         }
     }
 
+    /**
+     * Utility class for implementing DataNodeContainer-type statements.
+     */
+    public abstract static class DefaultDataNodeContainer<A, D extends DeclaredStatement<A>> extends Default<A, D>
+            implements DataNodeContainerMixin<A, D> {
+        private final @NonNull ImmutableMap<QName, DataSchemaNode> dataChildren;
+        private final @NonNull Object substatements;
+
+        protected DefaultDataNodeContainer(final D declared, final StatementSourceReference ref,
+                final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+            super(declared);
+            this.substatements = maskList(substatements);
+
+            // Note: we do not leak this map, so iteration order does not matter
+            final Map<QName, DataSchemaNode> tmp = new HashMap<>();
+
+            for (EffectiveStatement<?, ?> stmt : effectiveSubstatements()) {
+                if (stmt instanceof DataSchemaNode) {
+                    final DataSchemaNode node = (DataSchemaNode) stmt;
+                    final QName id = node.getQName();
+                    final DataSchemaNode prev = tmp.put(id, node);
+                    SourceException.throwIf(prev != null, ref,
+                            "Cannot add child with name %s, a conflicting child already exists", id);
+                }
+            }
+
+            dataChildren = ImmutableMap.copyOf(tmp);
+        }
+
+        @Override
+        public final ImmutableList<? extends EffectiveStatement<?, ?>> effectiveSubstatements() {
+            return unmaskList(substatements);
+        }
+
+        @Override
+        public final Optional<DataSchemaNode> findDataChildByName(final QName name) {
+            return Optional.ofNullable(dataChildren.get(requireNonNull(name)));
+        }
+    }
+
     /**
      * An extra building block on top of {@link Default}, which is wiring {@link #argument()} to the declared statement.
      * This is mostly useful for arguments that are not subject to inference transformation -- for example Strings in
index 9a7ba109d500cd11d4d93c51081d548e96f4ca3d..ef089c6e58612788e4a0c243e4b1a51f42851272 100644 (file)
@@ -7,20 +7,25 @@
  */
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.grouping;
 
+import com.google.common.collect.ImmutableList;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.GroupingEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.GroupingStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseQNameStatementSupport;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.EffectiveStatementWithFlags.FlagsBuilder;
 import org.opendaylight.yangtools.yang.parser.spi.GroupingNamespace;
-import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractQNameStatementSupport;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 
 abstract class AbstractGroupingStatementSupport
-        extends AbstractQNameStatementSupport<GroupingStatement, GroupingEffectiveStatement> {
-
+        extends BaseQNameStatementSupport<GroupingStatement, GroupingEffectiveStatement> {
     AbstractGroupingStatementSupport() {
         super(YangStmtMapping.GROUPING);
     }
@@ -30,27 +35,6 @@ abstract class AbstractGroupingStatementSupport
         return StmtContextUtils.parseIdentifier(ctx, value);
     }
 
-    @Override
-    public final GroupingStatement createDeclared(final StmtContext<QName, GroupingStatement, ?> ctx) {
-        // Shadowing check: make sure grandparent does not see a conflicting definition. This is required to ensure
-        // that a grouping in child scope does not shadow a grouping in parent scope which occurs later in the text.
-        final StmtContext<?, ?, ?> parent = ctx.getParentContext();
-        if (parent != null) {
-            final StmtContext<?, ?, ?> grandParent = parent.getParentContext();
-            if (grandParent != null) {
-                checkConflict(grandParent, ctx);
-            }
-        }
-
-        return new GroupingStatementImpl(ctx);
-    }
-
-    @Override
-    public final GroupingEffectiveStatement createEffective(
-            final StmtContext<QName, GroupingStatement, GroupingEffectiveStatement> ctx) {
-        return new GroupingEffectiveStatementImpl(ctx);
-    }
-
     @Override
     public final void onFullDefinitionDeclared(
             final Mutable<QName, GroupingStatement, GroupingEffectiveStatement> stmt) {
@@ -67,6 +51,51 @@ abstract class AbstractGroupingStatementSupport
         }
     }
 
+    @Override
+    protected final GroupingStatement createDeclared(final StmtContext<QName, GroupingStatement, ?> ctx,
+            final ImmutableList<? extends DeclaredStatement<?>> substatements) {
+        checkDeclaredConflict(ctx);
+        return new RegularGroupingStatement(ctx.coerceStatementArgument(), substatements);
+    }
+
+    @Override
+    protected final GroupingStatement createEmptyDeclared(final StmtContext<QName, GroupingStatement, ?> ctx) {
+        checkDeclaredConflict(ctx);
+        return new EmptyGroupingStatement(ctx.coerceStatementArgument());
+    }
+
+    @Override
+    protected final GroupingEffectiveStatement createEffective(
+            final StmtContext<QName, GroupingStatement, GroupingEffectiveStatement> ctx,
+            final GroupingStatement declared, final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+        final int flags = new FlagsBuilder()
+                .setHistory(ctx.getCopyHistory())
+                .setStatus(findFirstArgument(substatements, StatusEffectiveStatement.class, Status.CURRENT))
+                .toFlags();
+
+        return new GroupingEffectiveStatementImpl(declared, ctx.getSchemaPath().get(), flags, substatements,
+            ctx.getStatementSourceReference());
+    }
+
+    @Override
+    protected GroupingEffectiveStatement createEmptyEffective(
+            final StmtContext<QName, GroupingStatement, GroupingEffectiveStatement> ctx,
+            final GroupingStatement declared) {
+        return createEffective(ctx, declared, ImmutableList.of());
+    }
+
+    private static void checkDeclaredConflict(final StmtContext<QName, ?, ?> ctx) {
+        // Shadowing check: make sure grandparent does not see a conflicting definition. This is required to ensure
+        // that a grouping in child scope does not shadow a grouping in parent scope which occurs later in the text.
+        final StmtContext<?, ?, ?> parent = ctx.getParentContext();
+        if (parent != null) {
+            final StmtContext<?, ?, ?> grandParent = parent.getParentContext();
+            if (grandParent != null) {
+                checkConflict(grandParent, ctx);
+            }
+        }
+    }
+
     private static void checkConflict(final StmtContext<?, ?, ?> parent, final StmtContext<QName, ?, ?> stmt) {
         final QName arg = stmt.coerceStatementArgument();
         final StmtContext<?, ?, ?> existing = parent.getFromNamespace(GroupingNamespace.class, arg);
@@ -9,12 +9,10 @@ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.grouping;
 
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.stmt.GroupingStatement;
-import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement;
-import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractDeclaredStatement.WithQNameArgument;
 
-public class GroupingStatementImpl extends AbstractDeclaredStatement<QName>
-        implements GroupingStatement {
-    GroupingStatementImpl(final StmtContext<QName, GroupingStatement, ?> context) {
-        super(context);
+final class EmptyGroupingStatement extends WithQNameArgument implements GroupingStatement {
+    EmptyGroupingStatement(final QName argument) {
+        super(argument);
     }
 }
index 908ad243c73afb0f3a634d092b449e8e2ccdc1bc..d86998ae73832110385bc3b3f2c73c92a6f15d03 100644 (file)
@@ -7,87 +7,64 @@
  */
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.grouping;
 
-import com.google.common.collect.ImmutableSet;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableList;
 import java.util.Objects;
-import java.util.Set;
 import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
-import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.GroupingEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.GroupingStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.compat.ActionNodeContainerCompat;
 import org.opendaylight.yangtools.yang.model.api.stmt.compat.NotificationNodeContainerCompat;
-import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractEffectiveDocumentedDataNodeContainer;
-import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
-import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractDeclaredEffectiveStatement.DefaultDataNodeContainer;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.ActionNodeContainerMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.AddedByUsesMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.NotificationNodeContainerMixin;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.SchemaNodeMixin;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
 
 final class GroupingEffectiveStatementImpl
-        extends AbstractEffectiveDocumentedDataNodeContainer<QName, GroupingStatement>
+        extends DefaultDataNodeContainer<QName, GroupingStatement>
         implements GroupingDefinition, GroupingEffectiveStatement,
+            SchemaNodeMixin<QName, GroupingStatement>, ActionNodeContainerMixin<QName, GroupingStatement>,
             ActionNodeContainerCompat<QName, GroupingStatement>,
-            NotificationNodeContainerCompat<QName, GroupingStatement> {
-    private final @NonNull QName qname;
+            NotificationNodeContainerCompat<QName, GroupingStatement>,
+            NotificationNodeContainerMixin<QName, GroupingStatement>, AddedByUsesMixin<QName, GroupingStatement> {
     private final @NonNull SchemaPath path;
-    private final boolean addedByUses;
-    private final @NonNull ImmutableSet<ActionDefinition> actions;
-    private final @NonNull ImmutableSet<NotificationDefinition> notifications;
-
-    GroupingEffectiveStatementImpl(final StmtContext<QName, GroupingStatement, GroupingEffectiveStatement> ctx) {
-        super(ctx);
-
-        qname = ctx.coerceStatementArgument();
-        path = ctx.getSchemaPath().get();
-        addedByUses = ctx.getCopyHistory().contains(CopyType.ADDED_BY_USES);
-
-        final ImmutableSet.Builder<ActionDefinition> actionsBuilder = ImmutableSet.builder();
-        final ImmutableSet.Builder<NotificationDefinition> notificationsBuilder = ImmutableSet.builder();
-        for (final EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
-            if (effectiveStatement instanceof ActionDefinition) {
-                actionsBuilder.add((ActionDefinition) effectiveStatement);
-            }
-            if (effectiveStatement instanceof NotificationDefinition) {
-                notificationsBuilder.add((NotificationDefinition) effectiveStatement);
-            }
-        }
+    private final int flags;
 
-        this.actions = actionsBuilder.build();
-        this.notifications = notificationsBuilder.build();
+    GroupingEffectiveStatementImpl(final GroupingStatement declared, final SchemaPath path, final int flags,
+            final ImmutableList<? extends EffectiveStatement<?, ?>> substatements, final StatementSourceReference ref) {
+        super(declared, ref, substatements);
+        this.path = requireNonNull(path);
+        this.flags = flags;
     }
 
     @Override
-    public QName getQName() {
-        return qname;
+    public int flags() {
+        return flags;
     }
 
     @Override
-    public SchemaPath getPath() {
-        return path;
+    public @Nullable QName argument() {
+        return getQName();
     }
 
     @Override
-    public boolean isAddedByUses() {
-        return addedByUses;
-    }
-
-    @Override
-    public Set<ActionDefinition> getActions() {
-        return actions;
-    }
-
-    @Override
-    public Set<NotificationDefinition> getNotifications() {
-        return notifications;
+    public SchemaPath getPath() {
+        return path;
     }
 
     @Override
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + Objects.hashCode(qname);
+        result = prime * result + Objects.hashCode(getQName());
         result = prime * result + Objects.hashCode(path);
         return result;
     }
@@ -97,18 +74,15 @@ final class GroupingEffectiveStatementImpl
         if (this == obj) {
             return true;
         }
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
+        if (obj == null || getClass() != obj.getClass()) {
             return false;
         }
         final GroupingEffectiveStatementImpl other = (GroupingEffectiveStatementImpl) obj;
-        return Objects.equals(qname, other.qname) && Objects.equals(path, other.path);
+        return Objects.equals(getQName(), other.getQName()) && Objects.equals(path, other.path);
     }
 
     @Override
     public String toString() {
-        return GroupingEffectiveStatementImpl.class.getSimpleName() + "[" + "qname=" + qname + "]";
+        return GroupingEffectiveStatementImpl.class.getSimpleName() + "[" + "qname=" + getQName() + "]";
     }
 }
diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/grouping/RegularGroupingStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/grouping/RegularGroupingStatement.java
new file mode 100644 (file)
index 0000000..bc81d99
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.grouping;
+
+import com.google.common.collect.ImmutableList;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.GroupingStatement;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractDeclaredStatement.WithQNameArgument.WithSubstatements;
+
+final class RegularGroupingStatement extends WithSubstatements implements GroupingStatement {
+    RegularGroupingStatement(final QName argument, final ImmutableList<? extends DeclaredStatement<?>> substatements) {
+        super(argument, substatements);
+    }
+}