From: Robert Varga Date: Fri, 11 Nov 2016 02:46:54 +0000 (+0100) Subject: BUG-5717: add unique child identifier X-Git-Tag: release/carbon~240 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=819c9d65e9790f3cbfd85bfc2cf86b26af10553e;p=yangtools.git BUG-5717: add unique child identifier We need to synchronize the parse tree walker with the StatementWriter, so they can pair statements across multiple phases. Adjust StatementWriter to take an int childId to achieve this. Change-Id: Ie3e210a9084cbe5a86212046083c359393a912f8 Signed-off-by: Robert Varga --- diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangStatementParserListenerImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangStatementParserListenerImpl.java index c9bd2c61a4..45bde58754 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangStatementParserListenerImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangStatementParserListenerImpl.java @@ -8,7 +8,9 @@ package org.opendaylight.yangtools.yang.parser.impl; import com.google.common.base.Verify; +import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Deque; import java.util.List; import javax.annotation.concurrent.Immutable; import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.ArgumentContext; @@ -28,7 +30,16 @@ import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils; @Immutable public class YangStatementParserListenerImpl extends YangStatementParserBaseListener { + private static final class Counter { + private int value = 0; + + int getAndIncrement() { + return value++; + } + } + private final List toBeSkipped = new ArrayList<>(); + private final Deque counters = new ArrayDeque<>(); private final String sourceName; private QNameToStatementDefinition stmtDef; private PrefixToModule prefixes; @@ -41,12 +52,20 @@ public class YangStatementParserListenerImpl extends YangStatementParserBaseList public void setAttributes(final StatementWriter writer, final QNameToStatementDefinition stmtDef) { this.writer = writer; this.stmtDef = stmtDef; + initCounters(); } - public void setAttributes(final StatementWriter writer, final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes) { + public void setAttributes(final StatementWriter writer, final QNameToStatementDefinition stmtDef, + final PrefixToModule prefixes) { this.writer = writer; this.stmtDef = stmtDef; this.prefixes = prefixes; + initCounters(); + } + + private void initCounters() { + counters.clear(); + counters.push(new Counter()); } @Override @@ -57,6 +76,8 @@ public class YangStatementParserListenerImpl extends YangStatementParserBaseList final QName identifier = QName.create(YangConstants.RFC6020_YIN_MODULE, keywordTxt); final QName validStatementDefinition = Utils.getValidStatementDefinition(prefixes, stmtDef, identifier); + final int childId = counters.peek().getAndIncrement(); + counters.push(new Counter()); if (stmtDef == null || validStatementDefinition == null || !toBeSkipped.isEmpty()) { SourceException.throwIf(writer.getPhase() == ModelProcessingPhase.FULL_DECLARATION, ref, "%s is not a YANG statement or use of extension.", keywordTxt); @@ -66,7 +87,7 @@ public class YangStatementParserListenerImpl extends YangStatementParserBaseList final ArgumentContext argumentCtx = ctx.getChild(ArgumentContext.class, 0); final String argument = argumentCtx != null ? Utils.stringFromStringContext(argumentCtx) : null; - writer.startStatement(validStatementDefinition, argument, ref); + writer.startStatement(childId, validStatementDefinition, argument, ref); } @Override @@ -84,5 +105,6 @@ public class YangStatementParserListenerImpl extends YangStatementParserBaseList // No-op if the statement is not on the list toBeSkipped.remove(statementName); + counters.pop(); } } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/rfc6020/repo/YinStatementStreamSource.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/rfc6020/repo/YinStatementStreamSource.java index e162e801ba..05ceca6219 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/rfc6020/repo/YinStatementStreamSource.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/rfc6020/repo/YinStatementStreamSource.java @@ -87,7 +87,7 @@ public final class YinStatementStreamSource implements Identifiable *

* If statement has substatements, in order to start substatement, call to - * {@link #startStatement(QName, String, StatementSourceReference)} needs to be done + * {@link #startStatement(int, QName, String, StatementSourceReference)} needs to be done * for substatement. * + * @param childId + * Child identifier, unique among siblings + * * @param name * Fully qualified name of statement. * @param argument @@ -39,7 +42,8 @@ public interface StatementWriter { * @throws SourceException * if statement is not valid according to current context. */ - void startStatement(@Nonnull QName name, @Nullable String argument, @Nonnull StatementSourceReference ref); + void startStatement(final int childId, @Nonnull QName name, @Nullable String argument, + @Nonnull StatementSourceReference ref); /** * Ends current opened statement. diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java index 21499195a8..7b30b53f39 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java @@ -135,8 +135,8 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh return inProgressPhase; } - ContextBuilder createDeclaredChild(final StatementContextBase current, QName name, - final String argument, final StatementSourceReference ref) { + ContextBuilder createDeclaredChild(final StatementContextBase current, final int childId, + QName name, final String argument, final StatementSourceReference ref) { // FIXME: BUG-7038: Refactor/clean up this special case if (TYPE.equals(name)) { SourceException.throwIfNull(argument, ref, "Type statement requires an argument"); @@ -176,7 +176,7 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh if (current == null) { ret = new RootContextBuilder(def, ref); } else { - ret = current.substatementBuilder(def, ref); + ret = current.substatementBuilder(childId, def, ref); } if (argument != null) { diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java index 9d27131c64..d518069098 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java @@ -13,7 +13,6 @@ import com.google.common.base.Preconditions; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; @@ -22,12 +21,9 @@ import java.util.Collection; import java.util.Collections; import java.util.EnumMap; import java.util.EventListener; -import java.util.HashMap; import java.util.Iterator; -import java.util.Map; import javax.annotation.Nonnull; import org.opendaylight.yangtools.concepts.Identifiable; -import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping; 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.IdentifierNamespace; @@ -51,27 +47,20 @@ public abstract class StatementContextBase, E @SuppressWarnings({ "rawtypes", "unchecked" }) private final class SubContextBuilder extends ContextBuilder { - SubContextBuilder(final StatementDefinitionContext def, final StatementSourceReference sourceRef) { + final int childId; + + SubContextBuilder(final int childId, final StatementDefinitionContext def, + final StatementSourceReference sourceRef) { super(def, sourceRef); + this.childId = childId; } @Override public StatementContextBase build() { - StatementContextBase potential = null; - - final StatementDefinition stmtDef = getDefinition().getPublicView(); - // FIXME: this is rather ugly. Rather than having an explicit blacklist, StatementDefinitionContext should - // give us information whether we should really bother with the substatements map. - if (stmtDef != Rfc6020Mapping.AUGMENT && stmtDef != Rfc6020Mapping.DEVIATION - && stmtDef != Rfc6020Mapping.IMPORT && stmtDef != Rfc6020Mapping.TYPE) { - potential = substatements.get(createIdentifier()); - } + StatementContextBase potential = substatements.get(childId); if (potential == null) { potential = new SubstatementContext(StatementContextBase.this, this); - if (substatements.isEmpty()) { - substatements = new HashMap<>(1); - } - substatements.put(createIdentifier(), potential); + substatements = substatements.put(childId, potential); getDefinition().onStatementAdded(potential); } potential.resetLists(); @@ -121,10 +110,10 @@ public abstract class StatementContextBase, E private Multimap phaseListeners = ImmutableMultimap.of(); private Multimap phaseMutation = ImmutableMultimap.of(); - private Map> substatements = ImmutableMap.of(); private Collection> declared = ImmutableList.of(); private Collection> effective = ImmutableList.of(); private Collection> effectOfStatement = ImmutableList.of(); + private StatementMap substatements = StatementMap.empty(); private SupportedByFeatures supportedByFeatures = SupportedByFeatures.UNDEFINED; private CopyHistory copyHistory = CopyHistory.original(); @@ -403,9 +392,9 @@ public abstract class StatementContextBase, E * * @return instance of ContextBuilder */ - public ContextBuilder substatementBuilder(final StatementDefinitionContext def, + ContextBuilder substatementBuilder(final int childId, final StatementDefinitionContext def, final StatementSourceReference ref) { - return new SubContextBuilder(def, ref); + return new SubContextBuilder(childId, def, ref); } /** diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextWriter.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextWriter.java index 1e85389c68..8a8e4c2caa 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextWriter.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextWriter.java @@ -27,9 +27,10 @@ final class StatementContextWriter implements StatementWriter { } @Override - public void startStatement(final QName name, final String argument, final StatementSourceReference ref) { + public void startStatement(final int childId, final QName name, final String argument, + final StatementSourceReference ref) { deferredCreate(); - current = ctx.createDeclaredChild(parent, name, argument, ref); + current = ctx.createDeclaredChild(parent, childId, name, argument, ref); } @Override diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementMap.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementMap.java new file mode 100644 index 0000000000..0f28471fd2 --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementMap.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016 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.stmt.reactor; + +import com.google.common.base.Preconditions; +import java.util.Arrays; +import javax.annotation.Nonnull; + +/** + * Simple integer-to-StatementContextBase map optimized for size and restricted in scope of operations. + * + * @author Robert Varga + */ +abstract class StatementMap { + private static final class Empty extends StatementMap { + @Override + StatementContextBase get(final int index) { + return null; + } + + @Override + StatementMap put(final int index, final StatementContextBase object) { + return index == 0 ? new Singleton(object) : new Regular(index, object); + } + } + + private static final class Regular extends StatementMap { + private StatementContextBase[] elements; + + Regular(final int index, final StatementContextBase object) { + elements = new StatementContextBase[index + 1]; + elements[index] = Preconditions.checkNotNull(object); + } + + Regular(final StatementContextBase object0, final int index, + final StatementContextBase object) { + elements = new StatementContextBase[index + 1]; + elements[0] = Preconditions.checkNotNull(object0); + elements[index] = Preconditions.checkNotNull(object); + } + + @Override + StatementContextBase get(final int index) { + if (index >= elements.length) { + return null; + } + + return elements[index]; + } + + @Override + StatementMap put(final int index, final StatementContextBase object) { + if (index < elements.length) { + Preconditions.checkArgument(elements[index] == null); + } else { + elements = Arrays.copyOf(elements, index + 1); + } + + elements[index] = Preconditions.checkNotNull(object); + return this; + } + } + + private static final class Singleton extends StatementMap { + private final StatementContextBase object; + + Singleton(final StatementContextBase object) { + this.object = Preconditions.checkNotNull(object); + } + + @Override + StatementContextBase get(final int index) { + return index == 0 ? object : null; + } + + @Override + StatementMap put(final int index, final StatementContextBase object) { + Preconditions.checkArgument(index != 0); + return new Regular(this.object, index, object); + } + } + + private static final StatementMap EMPTY = new Empty(); + + static StatementMap empty() { + return EMPTY; + } + + abstract StatementContextBase get(int index); + abstract @Nonnull StatementMap put(int index, @Nonnull StatementContextBase object); +}