From 59f98cbf8ef79ecab8ee6d7c5141704142b0f40a Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Thu, 9 Jan 2020 00:22:32 +0100 Subject: [PATCH] Refactor Leaf(List)EffectiveStatementImpl Leaf(List)EffectiveStatementImpl costs 88 bytes each instance in common Linux deployment. This turns out to be unnecessary, as be can easily drop the size to 32/40 (48 worst) bytes by splitting out well-known constants. This can represent as much as 10% savings on retained heap. Since the two statements are sharing mapping towards SchemaNode world, we introduce EffectiveStatementMixins -- utility bridge interfaces, which are implementing aspects of DocumentedNode and its subclasses in terms of EffectiveStatement and some mixed-in state. JIRA: YANGTOOLS-1065 Change-Id: Icdafc4a196d86d2a493a44523bc81b1024854acb Signed-off-by: Robert Varga --- .../stmt/BaseQNameStatementSupport.java | 57 ++++ .../rfc7950/stmt/BaseStatementSupport.java | 17 + .../stmt/EffectiveStatementMixins.java | 319 ++++++++++++++++++ .../rfc7950/stmt/EffectiveStmtUtils.java | 27 +- .../leaf/AbstractLeafEffectiveStatement.java | 105 ++++++ .../leaf/EmptyLeafEffectiveStatement.java | 27 ++ .../stmt/leaf/LeafEffectiveStatementImpl.java | 124 ------- .../stmt/leaf/LeafStatementSupport.java | 61 +++- .../leaf/RegularLeafEffectiveStatement.java | 31 ++ .../AbstractLeafListEffectiveStatement.java | 136 ++++++++ .../AbstractLeafListStatementSupport.java | 79 ++++- ...actNonEmptyLeafListEffectiveStatement.java | 40 +++ .../EmptyLeafListEffectiveStatement.java | 41 +++ .../LeafListEffectiveStatementImpl.java | 147 -------- .../RegularLeafListEffectiveStatement.java | 35 ++ .../SlimLeafListEffectiveStatement.java | 29 ++ 16 files changed, 976 insertions(+), 299 deletions(-) create mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/BaseQNameStatementSupport.java create mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/EffectiveStatementMixins.java create mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/AbstractLeafEffectiveStatement.java create mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/EmptyLeafEffectiveStatement.java delete mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/LeafEffectiveStatementImpl.java create mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/RegularLeafEffectiveStatement.java create mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractLeafListEffectiveStatement.java create mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractNonEmptyLeafListEffectiveStatement.java create mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/EmptyLeafListEffectiveStatement.java delete mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/LeafListEffectiveStatementImpl.java create mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/RegularLeafListEffectiveStatement.java create mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/SlimLeafListEffectiveStatement.java diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/BaseQNameStatementSupport.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/BaseQNameStatementSupport.java new file mode 100644 index 0000000000..f359a485d2 --- /dev/null +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/BaseQNameStatementSupport.java @@ -0,0 +1,57 @@ +/* + * 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; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableList; +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.meta.DeclaredStatement; +import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; +import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractQNameStatementSupport; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; + +/** + * Specialization of {@link BaseStatementSupport} for QName statement arguments. + * + * @param Declared Statement representation + * @param Effective Statement representation + */ +@Beta +public abstract class BaseQNameStatementSupport, + E extends EffectiveStatement> extends AbstractQNameStatementSupport { + protected BaseQNameStatementSupport(final StatementDefinition publicDefinition) { + super(publicDefinition); + } + + @Override + public final E createEffective(final StmtContext ctx) { + final D declared = BaseStatementSupport.buildDeclared(ctx); + final ImmutableList> substatements = + BaseStatementSupport.buildEffectiveSubstatements(ctx); + return substatements.isEmpty() ? createEmptyEffective(ctx, declared) + : createEffective(ctx, declared, substatements); + } + + protected abstract @NonNull E createEffective(@NonNull StmtContext ctx, @NonNull D declared, + @NonNull ImmutableList> substatements); + + protected abstract @NonNull E createEmptyEffective(@NonNull StmtContext ctx, @NonNull D declared); + + protected static final > @Nullable E findFirstStatement( + final ImmutableList> statements, final Class type) { + return BaseStatementSupport.findFirstStatement(statements, type); + } + + protected static final > A findFirstArgument( + final ImmutableList> statements, final Class type, final A defValue) { + return BaseStatementSupport.findFirstArgument(statements, type, defValue); + } +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/BaseStatementSupport.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/BaseStatementSupport.java index 012d7cbaf5..ffb357c4e6 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/BaseStatementSupport.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/BaseStatementSupport.java @@ -17,6 +17,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; 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.meta.StatementDefinition; @@ -50,6 +51,22 @@ public abstract class BaseStatementSupport, protected abstract @NonNull E createEmptyEffective(@NonNull StmtContext ctx, @NonNull D declared); + protected static final > @Nullable E findFirstStatement( + final ImmutableList> statements, final Class type) { + for (EffectiveStatement stmt : statements) { + if (type.isInstance(stmt)) { + return type.cast(stmt); + } + } + return null; + } + + protected static final > A findFirstArgument( + final ImmutableList> statements, final Class type, final A defValue) { + final @Nullable E stmt = findFirstStatement(statements, type); + return stmt != null ? stmt.argument() : defValue; + } + static final > @NonNull D buildDeclared(final StmtContext ctx) { /* * Share original instance of declared statement between all effective diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/EffectiveStatementMixins.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/EffectiveStatementMixins.java new file mode 100644 index 0000000000..46f09b90f8 --- /dev/null +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/EffectiveStatementMixins.java @@ -0,0 +1,319 @@ +/* + * 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; + +import com.google.common.annotations.Beta; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.yangtools.concepts.Mutable; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.AddedByUsesAware; +import org.opendaylight.yangtools.yang.model.api.CopyableNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DocumentedNode; +import org.opendaylight.yangtools.yang.model.api.MandatoryAware; +import org.opendaylight.yangtools.yang.model.api.MustConstraintAware; +import org.opendaylight.yangtools.yang.model.api.MustDefinition; +import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.opendaylight.yangtools.yang.model.api.Status; +import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; +import org.opendaylight.yangtools.yang.model.api.WhenConditionAware; +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.DescriptionEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.WhenEffectiveStatement; +import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory; +import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType; + +/** + * Mix-in interfaces providing services required by SchemaNode et al. These interfaces provide implementations, or + * implementation helpers based on default methods, so the correct behavior can be logically centralized. + */ +@Beta +public final class EffectiveStatementMixins { + // Marker interface requiring all mixins to be derived from EffectiveStatement. + private interface Mixin> extends EffectiveStatement { + @SuppressWarnings("unchecked") + default Collection filterEffectiveStatements(final Class type) { + // Yeah, this is not nice, but saves one transformation + return (Collection) Collections2.filter(effectiveSubstatements(), type::isInstance); + } + + default List filterEffectiveStatementsList(final Class type) { + return effectiveSubstatements().stream().filter(type::isInstance).map(type::cast) + .collect(ImmutableList.toImmutableList()); + } + } + + /** + * Bridge between {@link EffectiveStatementWithFlags} and {@link AddedByUsesAware}. + * + * @param Argument type ({@link Void} if statement does not have argument.) + * @param Class representing declared version of this statement. + */ + public interface AddedByUsesMixin> + extends EffectiveStatementWithFlags, AddedByUsesAware { + @Override + default boolean isAddedByUses() { + return (flags() & FlagsBuilder.ADDED_BY_USES) != 0; + } + } + + /** + * Bridge between {@link EffectiveStatementWithFlags} and {@link MustConstraintAware}. + * + * @param Argument type ({@link Void} if statement does not have argument.) + * @param Class representing declared version of this statement. + */ + public interface MustConstraintMixin> extends Mixin, MustConstraintAware { + @Override + default Collection getMustConstraints() { + return filterEffectiveStatements(MustDefinition.class); + } + } + + /** + * Bridge between {@link EffectiveStatementWithFlags} and {@link CopyableNode}. + * + * @param Argument type ({@link Void} if statement does not have argument.) + * @param Class representing declared version of this statement. + */ + public interface CopyableMixin> extends AddedByUsesMixin, CopyableNode { + @Override + default boolean isAugmenting() { + return (flags() & FlagsBuilder.AUGMENTING) != 0; + } + } + + /** + * Bridge between {@link EffectiveStatementWithFlags} and {@link DataSchemaNode}. + * + * @param Argument type ({@link Void} if statement does not have argument.) + * @param Class representing declared version of this statement. + */ + public interface DataSchemaNodeMixin> + extends DataSchemaNode, CopyableMixin, SchemaNodeMixin, WhenConditionMixin { + @Override + default boolean isConfiguration() { + return (flags() & FlagsBuilder.CONFIGURATION) != 0; + } + } + + /** + * Bridge between {@link EffectiveStatementWithFlags} and {@link DocumentedNode}. + * + * @param Argument type ({@link Void} if statement does not have argument.) + * @param Class representing declared version of this statement. + */ + public interface DocumentedNodeMixin> extends Mixin, DocumentedNode { + /** + * Bridge between {@link EffectiveStatementWithFlags} and + * {@link org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus}. + * + * @param Argument type ({@link Void} if statement does not have argument.) + * @param Class representing declared version of this statement. + */ + interface WithStatus> + extends EffectiveStatementWithFlags, DocumentedNodeMixin, DocumentedNode.WithStatus { + @Override + default Status getStatus() { + final int status = flags() & FlagsBuilder.MASK_STATUS; + switch (status) { + case FlagsBuilder.STATUS_CURRENT: + return Status.CURRENT; + case FlagsBuilder.STATUS_DEPRECATED: + return Status.DEPRECATED; + case FlagsBuilder.STATUS_OBSOLETE: + return Status.OBSOLETE; + default: + throw new IllegalStateException("Illegal status " + status); + } + } + } + + @Override + default Optional getDescription() { + return findFirstEffectiveSubstatementArgument(DescriptionEffectiveStatement.class); + } + + @Override + default Optional getReference() { + return findFirstEffectiveSubstatementArgument(ReferenceEffectiveStatement.class); + } + + @Override + default List getUnknownSchemaNodes() { + return filterEffectiveStatementsList(UnknownSchemaNode.class); + } + } + + /** + * Bridge between {@link EffectiveStatementWithFlags} and {@link MandatoryAware}. + * + * @param Argument type ({@link Void} if statement does not have argument.) + * @param Class representing declared version of this statement. + */ + public interface MandatoryMixin> + extends EffectiveStatementWithFlags, MandatoryAware { + @Override + default boolean isMandatory() { + return (flags() & FlagsBuilder.MANDATORY) != 0; + } + } + + /** + * Bridge between {@link EffectiveStatementWithFlags} and {@link SchemaNode}. + * + * @param Argument type ({@link Void} if statement does not have argument.) + * @param Class representing declared version of this statement. + */ + public interface SchemaNodeMixin> + extends DocumentedNodeMixin.WithStatus, SchemaNode { + @Override + default QName getQName() { + return getPath().getLastComponent(); + } + } + + /** + * Bridge between {@link EffectiveStatementWithFlags} and {@code ordered-by} statement. + * + * @param Argument type ({@link Void} if statement does not have argument.) + * @param Class representing declared version of this statement. + */ + public interface UserOrderedMixin> extends EffectiveStatementWithFlags { + default boolean userOrdered() { + return (flags() & FlagsBuilder.USER_ORDERED) != 0; + } + } + + /** + * Helper used to locate the effective {@code when} statement and exposing its argument as per + * {@link WhenConditionAware}. + * + * @param Argument type ({@link Void} if statement does not have argument.) + * @param Class representing declared version of this statement. + */ + public interface WhenConditionMixin> extends Mixin, WhenConditionAware { + @Override + default Optional getWhenCondition() { + return findFirstEffectiveSubstatementArgument(WhenEffectiveStatement.class); + } + } + + /** + * Support interface for various mixins. Implementations are required to store 32bits worth of flags, which are + * globally assigned to sub-interfaces -- thus providing storage for many low-cardinality properties. + * + * @param Argument type ({@link Void} if statement does not have argument.) + * @param Class representing declared version of this statement. + */ + public interface EffectiveStatementWithFlags> extends Mixin { + /** + * Return flags assicated with this statements. Flags can be built using {@link FlagsBuilder}. + * + * @return Flag field value (32 bits). + */ + int flags(); + + @NonNullByDefault + final class FlagsBuilder implements Mutable { + // We still have 25 flags remaining + static final int STATUS_CURRENT = 0x0001; + static final int STATUS_DEPRECATED = 0x0002; + static final int STATUS_OBSOLETE = 0x0003; + static final int MASK_STATUS = 0x0003; + + static final int CONFIGURATION = 0x0004; + static final int MANDATORY = 0x0008; + + static final int AUGMENTING = 0x0010; + static final int ADDED_BY_USES = 0x0020; + private static final int MASK_HISTORY = 0x0030; + + static final int USER_ORDERED = 0x0040; + + private int flags; + + public FlagsBuilder setConfiguration(final boolean config) { + if (config) { + flags |= CONFIGURATION; + } else { + flags &= ~CONFIGURATION; + } + return this; + } + + public FlagsBuilder setHistory(final CopyHistory history) { + int bits; + if (history.contains(CopyType.ADDED_BY_USES_AUGMENTATION)) { + bits = AUGMENTING | ADDED_BY_USES; + } else { + bits = 0; + if (history.contains(CopyType.ADDED_BY_AUGMENTATION)) { + bits |= AUGMENTING; + } + if (history.contains(CopyType.ADDED_BY_USES)) { + bits |= ADDED_BY_USES; + } + } + + flags = flags & ~MASK_HISTORY | bits; + return this; + } + + public FlagsBuilder setMandatory(final boolean mandatory) { + if (mandatory) { + flags |= MANDATORY; + } else { + flags &= ~MANDATORY; + } + return this; + } + + public FlagsBuilder setStatus(final Status status) { + final int bits; + switch (status) { + case CURRENT: + bits = STATUS_CURRENT; + break; + case DEPRECATED: + bits = STATUS_DEPRECATED; + break; + case OBSOLETE: + bits = STATUS_DEPRECATED; + break; + default: + throw new IllegalStateException("Unhandled status " + status); + } + + flags = flags & ~MASK_STATUS | bits; + return this; + } + + public FlagsBuilder setUserOrdered(final boolean userOrdered) { + if (userOrdered) { + flags |= USER_ORDERED; + } else { + flags &= ~USER_ORDERED; + } + return this; + } + + public int toFlags() { + return flags; + } + } + } +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/EffectiveStmtUtils.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/EffectiveStmtUtils.java index 1c5af12b04..0b88f71393 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/EffectiveStmtUtils.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/EffectiveStmtUtils.java @@ -10,10 +10,12 @@ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt; import com.google.common.annotations.Beta; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; import java.util.HashSet; import java.util.Iterator; import java.util.Optional; import java.util.Set; +import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.YangVersion; import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint; @@ -48,19 +50,29 @@ public final class EffectiveStmtUtils { } public static Optional createElementCountConstraint(final EffectiveStatement stmt) { + return createElementCountConstraint( + stmt.findFirstEffectiveSubstatementArgument(MinElementsEffectiveStatement.class).orElse(null), + stmt.findFirstEffectiveSubstatementArgument(MaxElementsEffectiveStatement.class).orElse(null)); + } + + public static Optional createElementCountConstraint( + final ImmutableList> substatements) { + return createElementCountConstraint( + BaseQNameStatementSupport.findFirstArgument(substatements, MinElementsEffectiveStatement.class, null), + BaseQNameStatementSupport.findFirstArgument(substatements, MaxElementsEffectiveStatement.class, null)); + } + + private static Optional createElementCountConstraint( + final @Nullable Integer min, final @Nullable String max) { final Integer minElements; - final Optional min = stmt.findFirstEffectiveSubstatementArgument(MinElementsEffectiveStatement.class); - if (min.isPresent()) { - final Integer m = min.get(); - minElements = m > 0 ? m : null; + if (min != null) { + minElements = min > 0 ? min : null; } else { minElements = null; } final Integer maxElements; - final String max = stmt.findFirstEffectiveSubstatementArgument(MaxElementsEffectiveStatement.class) - .orElse(UNBOUNDED_STR); - if (!UNBOUNDED_STR.equals(max)) { + if (max != null && !UNBOUNDED_STR.equals(max)) { final Integer m = Integer.valueOf(max); maxElements = m < Integer.MAX_VALUE ? m : null; } else { @@ -70,7 +82,6 @@ public final class EffectiveStmtUtils { return ElementCountConstraint.forNullable(minElements, maxElements); } - /** * Checks whether supplied type has any of specified default values marked * with an if-feature. This method creates mutable copy of supplied set of diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/AbstractLeafEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/AbstractLeafEffectiveStatement.java new file mode 100644 index 0000000000..d9c599fa34 --- /dev/null +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/AbstractLeafEffectiveStatement.java @@ -0,0 +1,105 @@ +/* + * 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.leaf; + +import static com.google.common.base.Verify.verify; +import static java.util.Objects.requireNonNull; + +import com.google.common.collect.ImmutableList; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.DefaultEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.LeafEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.LeafStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.UnitsEffectiveStatement; +import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypeBuilder; +import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypes; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractDeclaredEffectiveStatement; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.DataSchemaNodeMixin; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.MandatoryMixin; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.MustConstraintMixin; + +abstract class AbstractLeafEffectiveStatement extends AbstractDeclaredEffectiveStatement.Default + implements LeafEffectiveStatement, LeafSchemaNode, DerivableSchemaNode, + DataSchemaNodeMixin, MandatoryMixin, + MustConstraintMixin { + // Variable: either a single substatement or an ImmutableList + private final @NonNull Object substatements; + private final @NonNull SchemaPath path; + private final @NonNull TypeDefinition type; + private final int flags; + + AbstractLeafEffectiveStatement(final LeafStatement declared, final SchemaPath path, final int flags, + final ImmutableList> substatements) { + super(declared); + this.substatements = substatements.size() == 1 ? substatements.get(0) : substatements; + this.path = requireNonNull(path); + this.flags = flags; + // TODO: lazy instantiation? + this.type = buildType(); + } + + @Override + @SuppressWarnings("unchecked") + public final ImmutableList> effectiveSubstatements() { + if (substatements instanceof ImmutableList) { + return (ImmutableList>) substatements; + } + verify(substatements instanceof EffectiveStatement, "Unexpected substatement %s", substatements); + return ImmutableList.of((EffectiveStatement) substatements); + } + + @Override + public final int flags() { + return flags; + } + + @Override + public final @NonNull QName argument() { + return getQName(); + } + + @Override + public final @NonNull SchemaPath getPath() { + return path; + } + + @Override + public final TypeDefinition getType() { + return type; + } + + private TypeDefinition buildType() { + final TypeEffectiveStatement typeStmt = findFirstEffectiveSubstatement(TypeEffectiveStatement.class).get(); + final ConcreteTypeBuilder builder = ConcreteTypes.concreteTypeBuilder(typeStmt.getTypeDefinition(), + getPath()); + for (final EffectiveStatement stmt : effectiveSubstatements()) { + if (stmt instanceof DefaultEffectiveStatement) { + builder.setDefaultValue(((DefaultEffectiveStatement)stmt).argument()); + } else if (stmt instanceof DescriptionEffectiveStatement) { + builder.setDescription(((DescriptionEffectiveStatement)stmt).argument()); + } else if (stmt instanceof ReferenceEffectiveStatement) { + builder.setReference(((ReferenceEffectiveStatement)stmt).argument()); + } else if (stmt instanceof StatusEffectiveStatement) { + builder.setStatus(((StatusEffectiveStatement)stmt).argument()); + } else if (stmt instanceof UnitsEffectiveStatement) { + builder.setUnits(((UnitsEffectiveStatement)stmt).argument()); + } + } + return builder.build(); + } +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/EmptyLeafEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/EmptyLeafEffectiveStatement.java new file mode 100644 index 0000000000..a72b500b1c --- /dev/null +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/EmptyLeafEffectiveStatement.java @@ -0,0 +1,27 @@ +/* + * 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.leaf; + +import com.google.common.collect.ImmutableList; +import java.util.Optional; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +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.LeafStatement; + +final class EmptyLeafEffectiveStatement extends AbstractLeafEffectiveStatement { + EmptyLeafEffectiveStatement(final LeafStatement declared, final SchemaPath path, final int flags, + final ImmutableList> substatements) { + super(declared, path, flags, substatements); + } + + @Override + public Optional getOriginal() { + return Optional.empty(); + } +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/LeafEffectiveStatementImpl.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/LeafEffectiveStatementImpl.java deleted file mode 100644 index 3c6666780f..0000000000 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/LeafEffectiveStatementImpl.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2015 Cisco Systems, Inc. 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.leaf; - -import java.util.Objects; -import java.util.Optional; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode; -import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; -import org.opendaylight.yangtools.yang.model.api.TypeDefinition; -import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.DefaultEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.LeafEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.LeafStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.MandatoryEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.UnitsEffectiveStatement; -import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypeBuilder; -import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypes; -import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractEffectiveMustConstraintAwareDataSchemaNode; -import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStmtUtils; -import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; -import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; - -final class LeafEffectiveStatementImpl extends AbstractEffectiveMustConstraintAwareDataSchemaNode - implements LeafEffectiveStatement, LeafSchemaNode, DerivableSchemaNode { - private final LeafSchemaNode original; - private final TypeDefinition type; - private final String defaultStr; - private final String unitsStr; - private final boolean mandatory; - - LeafEffectiveStatementImpl(final StmtContext> ctx) { - super(ctx); - this.original = (LeafSchemaNode) ctx.getOriginalCtx().map(StmtContext::buildEffective).orElse(null); - - final TypeEffectiveStatement typeStmt = SourceException.throwIfNull( - firstSubstatementOfType(TypeEffectiveStatement.class), ctx.getStatementSourceReference(), - "Leaf is missing a 'type' statement"); - - String dflt = null; - String units = null; - final ConcreteTypeBuilder builder = ConcreteTypes.concreteTypeBuilder(typeStmt.getTypeDefinition(), - ctx.getSchemaPath().get()); - for (final EffectiveStatement stmt : effectiveSubstatements()) { - if (stmt instanceof DefaultEffectiveStatement) { - dflt = ((DefaultEffectiveStatement)stmt).argument(); - builder.setDefaultValue(stmt.argument()); - } else if (stmt instanceof DescriptionEffectiveStatement) { - builder.setDescription(((DescriptionEffectiveStatement)stmt).argument()); - } else if (stmt instanceof ReferenceEffectiveStatement) { - builder.setReference(((ReferenceEffectiveStatement)stmt).argument()); - } else if (stmt instanceof StatusEffectiveStatement) { - builder.setStatus(((StatusEffectiveStatement)stmt).argument()); - } else if (stmt instanceof UnitsEffectiveStatement) { - units = ((UnitsEffectiveStatement)stmt).argument(); - builder.setUnits(units); - } - } - - SourceException.throwIf( - EffectiveStmtUtils.hasDefaultValueMarkedWithIfFeature(ctx.getRootVersion(), typeStmt, dflt), - ctx.getStatementSourceReference(), - "Leaf '%s' has default value '%s' marked with an if-feature statement.", ctx.getStatementArgument(), dflt); - - defaultStr = dflt; - unitsStr = units; - type = builder.build(); - mandatory = findFirstEffectiveSubstatementArgument(MandatoryEffectiveStatement.class).orElse(Boolean.FALSE) - .booleanValue(); - } - - @Override - public boolean isMandatory() { - return mandatory; - } - - @Override - public Optional getOriginal() { - return Optional.ofNullable(original); - } - - @Override - public TypeDefinition getType() { - return type; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + Objects.hashCode(getQName()); - result = prime * result + Objects.hashCode(getPath()); - return result; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof LeafEffectiveStatementImpl)) { - return false; - } - final LeafEffectiveStatementImpl other = (LeafEffectiveStatementImpl) obj; - return Objects.equals(getQName(), other.getQName()) && Objects.equals(getPath(), other.getPath()); - } - - @Override - public String toString() { - return LeafEffectiveStatementImpl.class.getSimpleName() + "[" - + "qname=" + getQName() - + ", path=" + getPath() - + "]"; - } -} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/LeafStatementSupport.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/LeafStatementSupport.java index 488009e370..fdc13903d7 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/LeafStatementSupport.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/LeafStatementSupport.java @@ -7,19 +7,30 @@ */ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.leaf; +import com.google.common.collect.ImmutableList; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.Status; import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.DefaultEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.LeafEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.LeafStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.MandatoryEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement; import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ChildSchemaNodeNamespace; -import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractQNameStatementSupport; +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.rfc7950.stmt.EffectiveStmtUtils; 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.meta.SubstatementValidator; +import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; -public final class LeafStatementSupport - extends AbstractQNameStatementSupport> { +public final class LeafStatementSupport extends BaseQNameStatementSupport { private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(YangStmtMapping .LEAF) .addOptional(YangStmtMapping.CONFIG) @@ -50,13 +61,12 @@ public final class LeafStatementSupport } @Override - public void onStatementAdded(final Mutable> stmt) { + public void onStatementAdded(final Mutable stmt) { stmt.coerceParentContext().addToNs(ChildSchemaNodeNamespace.class, stmt.coerceStatementArgument(), stmt); } @Override - public void onFullDefinitionDeclared( - final Mutable> ctx) { + public void onFullDefinitionDeclared(final Mutable ctx) { super.onFullDefinitionDeclared(ctx); StmtContextUtils.validateIfFeatureAndWhenOnListKeys(ctx); } @@ -67,13 +77,40 @@ public final class LeafStatementSupport } @Override - public EffectiveStatement createEffective( - final StmtContext> ctx) { - return new LeafEffectiveStatementImpl(ctx); + protected SubstatementValidator getSubstatementValidator() { + return SUBSTATEMENT_VALIDATOR; } @Override - protected SubstatementValidator getSubstatementValidator() { - return SUBSTATEMENT_VALIDATOR; + protected LeafEffectiveStatement createEffective( + final StmtContext ctx, final LeafStatement declared, + final ImmutableList> substatements) { + final TypeEffectiveStatement typeStmt = SourceException.throwIfNull( + findFirstStatement(substatements, TypeEffectiveStatement.class), ctx.getStatementSourceReference(), + "Leaf is missing a 'type' statement"); + final String dflt = findFirstArgument(substatements, DefaultEffectiveStatement.class, null); + SourceException.throwIf( + EffectiveStmtUtils.hasDefaultValueMarkedWithIfFeature(ctx.getRootVersion(), typeStmt, dflt), + ctx.getStatementSourceReference(), + "Leaf '%s' has default value '%s' marked with an if-feature statement.", ctx.getStatementArgument(), dflt); + + final SchemaPath path = ctx.getSchemaPath().get(); + final LeafSchemaNode original = (LeafSchemaNode) ctx.getOriginalCtx().map(StmtContext::buildEffective) + .orElse(null); + final int flags = new FlagsBuilder() + .setHistory(ctx.getCopyHistory()) + .setStatus(findFirstArgument(substatements, StatusEffectiveStatement.class, Status.CURRENT)) + .setConfiguration(ctx.isConfiguration()) + .setMandatory(findFirstArgument(substatements, MandatoryEffectiveStatement.class, Boolean.FALSE)) + .toFlags(); + + return original == null ? new EmptyLeafEffectiveStatement(declared, path, flags, substatements) + : new RegularLeafEffectiveStatement(declared, path, flags, substatements, original); + } + + @Override + protected LeafEffectiveStatement createEmptyEffective( + final StmtContext ctx, final LeafStatement declared) { + throw new UnsupportedOperationException("Leaf statements must have at least one substatement"); } -} \ No newline at end of file +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/RegularLeafEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/RegularLeafEffectiveStatement.java new file mode 100644 index 0000000000..283564385c --- /dev/null +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf/RegularLeafEffectiveStatement.java @@ -0,0 +1,31 @@ +/* + * 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.leaf; + +import com.google.common.collect.ImmutableList; +import java.util.Optional; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +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.LeafStatement; + +final class RegularLeafEffectiveStatement extends AbstractLeafEffectiveStatement { + private final @Nullable LeafSchemaNode original; + + RegularLeafEffectiveStatement(final LeafStatement declared, final SchemaPath path, final int flags, + final ImmutableList> substatements, final LeafSchemaNode original) { + super(declared, path, flags, substatements); + this.original = original; + } + + @Override + public Optional getOriginal() { + return Optional.ofNullable(original); + } +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractLeafListEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractLeafListEffectiveStatement.java new file mode 100644 index 0000000000..bd30991073 --- /dev/null +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractLeafListEffectiveStatement.java @@ -0,0 +1,136 @@ +/* + * 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.leaf_list; + +import static com.google.common.base.Verify.verify; +import static java.util.Objects.requireNonNull; + +import com.google.common.collect.ImmutableList; +import java.util.Objects; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.LeafListEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.LeafListStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.UnitsEffectiveStatement; +import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypeBuilder; +import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypes; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractDeclaredEffectiveStatement; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.DataSchemaNodeMixin; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.MustConstraintMixin; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.UserOrderedMixin; + +abstract class AbstractLeafListEffectiveStatement + extends AbstractDeclaredEffectiveStatement.Default + implements LeafListEffectiveStatement, LeafListSchemaNode, DerivableSchemaNode, + UserOrderedMixin, DataSchemaNodeMixin, + MustConstraintMixin { + // Variable: either a single substatement or an ImmutableList + private final @NonNull Object substatements; + private final @NonNull SchemaPath path; + private final @NonNull TypeDefinition type; + private final int flags; + + AbstractLeafListEffectiveStatement(final LeafListStatement declared, final SchemaPath path, final int flags, + final ImmutableList> substatements) { + super(declared); + this.substatements = substatements.size() == 1 ? substatements.get(0) : substatements; + this.path = requireNonNull(path); + this.flags = flags; + // TODO: lazy instantiation? + this.type = buildType(); + } + + @Override + @SuppressWarnings("unchecked") + public final ImmutableList> effectiveSubstatements() { + if (substatements instanceof ImmutableList) { + return (ImmutableList>) substatements; + } + verify(substatements instanceof EffectiveStatement, "Unexpected substatement %s", substatements); + return ImmutableList.of((EffectiveStatement) substatements); + } + + @Override + public final int flags() { + return flags; + } + + @Override + public final @NonNull QName argument() { + return getQName(); + } + + @Override + public final @NonNull SchemaPath getPath() { + return path; + } + + @Override + public final TypeDefinition getType() { + return type; + } + + @Override + public final boolean isUserOrdered() { + return userOrdered(); + } + + @Override + public final int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Objects.hashCode(getQName()); + result = prime * result + Objects.hashCode(getPath()); + return result; + } + + @Override + public final boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof AbstractLeafListEffectiveStatement)) { + return false; + } + final AbstractLeafListEffectiveStatement other = (AbstractLeafListEffectiveStatement) obj; + return Objects.equals(getQName(), other.getQName()) && Objects.equals(getPath(), other.getPath()); + } + + @Override + public final String toString() { + return getClass().getSimpleName() + "[" + getQName() + "]"; + } + + private TypeDefinition buildType() { + final TypeEffectiveStatement typeStmt = findFirstEffectiveSubstatement(TypeEffectiveStatement.class).get(); + final ConcreteTypeBuilder builder = ConcreteTypes.concreteTypeBuilder(typeStmt.getTypeDefinition(), + getPath()); + for (final EffectiveStatement stmt : effectiveSubstatements()) { + // NOTE: 'default' is ommitted here on purpose + if (stmt instanceof DescriptionEffectiveStatement) { + builder.setDescription(((DescriptionEffectiveStatement)stmt).argument()); + } else if (stmt instanceof ReferenceEffectiveStatement) { + builder.setReference(((ReferenceEffectiveStatement)stmt).argument()); + } else if (stmt instanceof StatusEffectiveStatement) { + builder.setStatus(((StatusEffectiveStatement)stmt).argument()); + } else if (stmt instanceof UnitsEffectiveStatement) { + builder.setUnits(((UnitsEffectiveStatement)stmt).argument()); + } + } + return builder.build(); + } +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractLeafListStatementSupport.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractLeafListStatementSupport.java index 9ecb77f3e8..9dda6fbeb5 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractLeafListStatementSupport.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractLeafListStatementSupport.java @@ -7,26 +7,39 @@ */ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.leaf_list; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import java.util.Optional; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint; +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.Status; import org.opendaylight.yangtools.yang.model.api.YangStmtMapping; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.DefaultEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.LeafListEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.LeafListStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.OrderedByEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement; import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ChildSchemaNodeNamespace; -import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractQNameStatementSupport; +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.rfc7950.stmt.EffectiveStmtUtils; 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 AbstractLeafListStatementSupport - extends AbstractQNameStatementSupport> { - + extends BaseQNameStatementSupport { AbstractLeafListStatementSupport() { super(YangStmtMapping.LEAF_LIST); } @Override - public final void onStatementAdded( - final Mutable> stmt) { + public final void onStatementAdded(final Mutable stmt) { stmt.coerceParentContext().addToNs(ChildSchemaNodeNamespace.class, stmt.coerceStatementArgument(), stmt); } @@ -41,8 +54,58 @@ abstract class AbstractLeafListStatementSupport } @Override - public final EffectiveStatement createEffective( - final StmtContext> ctx) { - return new LeafListEffectiveStatementImpl(ctx); + protected final LeafListEffectiveStatement createEffective( + final StmtContext ctx, + final LeafListStatement declared, + final ImmutableList> substatements) { + final TypeEffectiveStatement typeStmt = SourceException.throwIfNull( + findFirstStatement(substatements, TypeEffectiveStatement.class), ctx.getStatementSourceReference(), + "Leaf-list is missing a 'type' statement"); + + final SchemaPath path = ctx.getSchemaPath().get(); + final LeafListSchemaNode original = (LeafListSchemaNode) ctx.getOriginalCtx() + .map(StmtContext::buildEffective).orElse(null); + + final int flags = new FlagsBuilder() + .setHistory(ctx.getCopyHistory()) + .setStatus(findFirstArgument(substatements, StatusEffectiveStatement.class, Status.CURRENT)) + .setConfiguration(ctx.isConfiguration()) + .setUserOrdered(findFirstArgument(substatements, OrderedByEffectiveStatement.class, "system") + .equals("user")) + .toFlags(); + final ImmutableSet defaultValues = substatements.stream() + .filter(DefaultEffectiveStatement.class::isInstance) + .map(DefaultEffectiveStatement.class::cast) + .map(DefaultEffectiveStatement::argument) + .collect(ImmutableSet.toImmutableSet()); + + // FIXME: We need to interpret the default value in terms of supplied element type + SourceException.throwIf( + EffectiveStmtUtils.hasDefaultValueMarkedWithIfFeature(ctx.getRootVersion(), typeStmt, defaultValues), + ctx.getStatementSourceReference(), + "Leaf-list '%s' has one of its default values '%s' marked with an if-feature statement.", + ctx.getStatementArgument(), defaultValues); + + // FIXME: RFC7950 section 7.7.4: we need to check for min-elements and defaultValues conflict + + final Optional elementCountConstraint = + EffectiveStmtUtils.createElementCountConstraint(substatements); + + if (defaultValues.isEmpty()) { + return original == null && !elementCountConstraint.isPresent() + ? new EmptyLeafListEffectiveStatement(declared, path, flags, substatements) + : new SlimLeafListEffectiveStatement(declared, path, flags, substatements, original, + elementCountConstraint.orElse(null)); + } + + return new RegularLeafListEffectiveStatement(declared, path, flags, substatements, original, defaultValues, + elementCountConstraint.orElse(null)); + } + + @Override + protected final LeafListEffectiveStatement createEmptyEffective( + final StmtContext ctx, + final LeafListStatement declared) { + throw new UnsupportedOperationException("Leaf statements must have at least one substatement"); } } \ No newline at end of file diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractNonEmptyLeafListEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractNonEmptyLeafListEffectiveStatement.java new file mode 100644 index 0000000000..950f2bc6c3 --- /dev/null +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/AbstractNonEmptyLeafListEffectiveStatement.java @@ -0,0 +1,40 @@ +/* + * 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.leaf_list; + +import com.google.common.collect.ImmutableList; +import java.util.Optional; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint; +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; +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.LeafListStatement; + +abstract class AbstractNonEmptyLeafListEffectiveStatement extends AbstractLeafListEffectiveStatement { + private final @Nullable LeafListSchemaNode original; + private final @Nullable ElementCountConstraint elementCountConstraint; + + AbstractNonEmptyLeafListEffectiveStatement(final LeafListStatement declared, final SchemaPath path, final int flags, + final ImmutableList> substatements, + final LeafListSchemaNode original, final ElementCountConstraint elementCountConstraint) { + super(declared, path, flags, substatements); + this.original = original; + this.elementCountConstraint = elementCountConstraint; + } + + @Override + public final Optional getOriginal() { + return Optional.ofNullable(original); + } + + @Override + public final Optional getElementCountConstraint() { + return Optional.ofNullable(elementCountConstraint); + } +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/EmptyLeafListEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/EmptyLeafListEffectiveStatement.java new file mode 100644 index 0000000000..7905da1793 --- /dev/null +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/EmptyLeafListEffectiveStatement.java @@ -0,0 +1,41 @@ +/* + * 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.leaf_list; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import java.util.Collection; +import java.util.Optional; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +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.LeafListStatement; + +final class EmptyLeafListEffectiveStatement extends AbstractLeafListEffectiveStatement { + EmptyLeafListEffectiveStatement(final LeafListStatement declared, final SchemaPath path, final int flags, + final ImmutableList> substatements) { + super(declared, path, flags, substatements); + } + + @Override + public Optional getOriginal() { + return Optional.empty(); + } + + @Override + public @NonNull Collection getDefaults() { + return ImmutableSet.of(); + } + + @Override + public Optional getElementCountConstraint() { + return Optional.empty(); + } +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/LeafListEffectiveStatementImpl.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/LeafListEffectiveStatementImpl.java deleted file mode 100644 index 6edbb70da4..0000000000 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/LeafListEffectiveStatementImpl.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2015 Cisco Systems, Inc. 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.leaf_list; - -import com.google.common.collect.ImmutableSet; -import java.util.Collection; -import java.util.Objects; -import java.util.Optional; -import org.eclipse.jdt.annotation.NonNull; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode; -import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint; -import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.TypeDefinition; -import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.DefaultEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.LeafListEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.LeafListStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.OrderedByEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.UnitsEffectiveStatement; -import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypeBuilder; -import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypes; -import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractEffectiveMustConstraintAwareDataSchemaNode; -import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStmtUtils; -import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; -import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; - -final class LeafListEffectiveStatementImpl extends AbstractEffectiveMustConstraintAwareDataSchemaNode - implements LeafListEffectiveStatement, LeafListSchemaNode, DerivableSchemaNode { - - private static final String ORDER_BY_USER_KEYWORD = "user"; - - private final TypeDefinition type; - private final LeafListSchemaNode original; - private final boolean userOrdered; - private final @NonNull ImmutableSet defaultValues; - private final ElementCountConstraint elementCountConstraint; - - LeafListEffectiveStatementImpl( - final StmtContext> ctx) { - super(ctx); - this.original = (LeafListSchemaNode) ctx.getOriginalCtx().map(StmtContext::buildEffective).orElse(null); - - final TypeEffectiveStatement typeStmt = SourceException.throwIfNull( - firstSubstatementOfType(TypeEffectiveStatement.class), ctx.getStatementSourceReference(), - "Leaf-list is missing a 'type' statement"); - - final ConcreteTypeBuilder builder = ConcreteTypes.concreteTypeBuilder(typeStmt.getTypeDefinition(), - ctx.getSchemaPath().get()); - final ImmutableSet.Builder defaultValuesBuilder = ImmutableSet.builder(); - boolean isUserOrdered = false; - for (final EffectiveStatement stmt : effectiveSubstatements()) { - if (stmt instanceof OrderedByEffectiveStatement) { - isUserOrdered = ORDER_BY_USER_KEYWORD.equals(stmt.argument()); - } - - if (stmt instanceof DefaultEffectiveStatement) { - defaultValuesBuilder.add(((DefaultEffectiveStatement) stmt).argument()); - } else if (stmt instanceof DescriptionEffectiveStatement) { - builder.setDescription(((DescriptionEffectiveStatement)stmt).argument()); - } else if (stmt instanceof ReferenceEffectiveStatement) { - builder.setReference(((ReferenceEffectiveStatement)stmt).argument()); - } else if (stmt instanceof StatusEffectiveStatement) { - builder.setStatus(((StatusEffectiveStatement)stmt).argument()); - } else if (stmt instanceof UnitsEffectiveStatement) { - builder.setUnits(((UnitsEffectiveStatement)stmt).argument()); - } - } - - // FIXME: We need to interpret the default value in terms of supplied element type - defaultValues = defaultValuesBuilder.build(); - SourceException.throwIf( - EffectiveStmtUtils.hasDefaultValueMarkedWithIfFeature(ctx.getRootVersion(), typeStmt, defaultValues), - ctx.getStatementSourceReference(), - "Leaf-list '%s' has one of its default values '%s' marked with an if-feature statement.", - ctx.getStatementArgument(), defaultValues); - - // FIXME: RFC7950 section 7.7.4: we need to check for min-elements and defaultValues conflict - - type = builder.build(); - userOrdered = isUserOrdered; - elementCountConstraint = EffectiveStmtUtils.createElementCountConstraint(this).orElse(null); - } - - @Override - public Collection getDefaults() { - return defaultValues; - } - - @Override - public Optional getOriginal() { - return Optional.ofNullable(original); - } - - @Override - public TypeDefinition getType() { - return type; - } - - @Override - public boolean isUserOrdered() { - return userOrdered; - } - - @Override - public Optional getElementCountConstraint() { - return Optional.ofNullable(elementCountConstraint); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + Objects.hashCode(getQName()); - result = prime * result + Objects.hashCode(getPath()); - return result; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final LeafListEffectiveStatementImpl other = (LeafListEffectiveStatementImpl) obj; - return Objects.equals(getQName(), other.getQName()) && Objects.equals(getPath(), other.getPath()); - } - - @Override - public String toString() { - return LeafListEffectiveStatementImpl.class.getSimpleName() + "[" + getQName() + "]"; - } -} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/RegularLeafListEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/RegularLeafListEffectiveStatement.java new file mode 100644 index 0000000000..d03f3d01c6 --- /dev/null +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/RegularLeafListEffectiveStatement.java @@ -0,0 +1,35 @@ +/* + * 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.leaf_list; + +import static java.util.Objects.requireNonNull; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint; +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; +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.LeafListStatement; + +final class RegularLeafListEffectiveStatement extends AbstractNonEmptyLeafListEffectiveStatement { + private final @NonNull ImmutableSet defaults; + + RegularLeafListEffectiveStatement(final LeafListStatement declared, final SchemaPath path, final int flags, + final ImmutableList> substatements, final LeafListSchemaNode original, + final ImmutableSet defaults, final ElementCountConstraint elementCountConstraint) { + super(declared, path, flags, substatements, original, elementCountConstraint); + this.defaults = requireNonNull(defaults); + } + + @Override + public ImmutableSet getDefaults() { + return defaults; + } +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/SlimLeafListEffectiveStatement.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/SlimLeafListEffectiveStatement.java new file mode 100644 index 0000000000..fdc7be3d1d --- /dev/null +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/leaf_list/SlimLeafListEffectiveStatement.java @@ -0,0 +1,29 @@ +/* + * 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.leaf_list; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint; +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; +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.LeafListStatement; + +final class SlimLeafListEffectiveStatement extends AbstractNonEmptyLeafListEffectiveStatement { + SlimLeafListEffectiveStatement(final LeafListStatement declared, final SchemaPath path, final int flags, + final ImmutableList> substatements, + final LeafListSchemaNode original, final ElementCountConstraint elementCountConstraint) { + super(declared, path, flags, substatements, original, elementCountConstraint); + } + + @Override + public ImmutableSet getDefaults() { + return ImmutableSet.of(); + } +} -- 2.36.6