package org.opendaylight.yangtools.yang.parser.spi.meta;
import com.google.common.base.Preconditions;
+import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.opendaylight.yangtools.yang.common.QName;
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.SubstatementValidator;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementDefinitionContext;
/**
*
return type;
}
+ @Override
+ public Optional<StatementContextBase<?, ?, ?>> beforeSubStatementCreated(final StmtContext.Mutable<?, ?, ?> stmt,
+ final int offset, final StatementDefinitionContext<?, ?, ?> def, final StatementSourceReference ref,
+ final String argument) {
+ // NOOP for most implementations and also no implicit statements
+ return Optional.empty();
+ }
+
@Override
public void onStatementAdded(final StmtContext.Mutable<A, D, E> stmt) {
// NOOP for most implementations
package org.opendaylight.yangtools.yang.parser.spi.meta;
+import java.util.Optional;
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.StmtContext.Mutable;
import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementDefinitionContext;
/**
*
*/
void onStatementAdded(StmtContext.Mutable<A, D, E> stmt);
+ /**
+ * Invoked before a substatement with specified offset, definition,
+ * reference and argument is created and added to parent statement. This
+ * allows implementations of this interface perform any modifications to the
+ * build context hierarchy before a substatement is created. One such use is
+ * creating an implicit statement.
+ *
+ * @param stmt
+ * Context of parent statement where a new substatement should be
+ * created. No substatements are available.
+ * @param offset
+ * substatement offset
+ * @param def
+ * definition context
+ * @param ref
+ * source reference
+ * @param argument
+ * substatement argument
+ * @return optional of an implicit substatement
+ */
+ Optional<StatementContextBase<?, ?, ?>> beforeSubStatementCreated(final Mutable<?, ?, ?> stmt, final int offset,
+ final StatementDefinitionContext<?, ?, ?> def, final StatementSourceReference ref, final String argument);
+
/**
* Invoked when statement is closed during
* {@link ModelProcessingPhase#SOURCE_PRE_LINKAGE} phase, only substatements
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;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
QName name, final String argument, final StatementSourceReference ref) {
if (current != null) {
// Fast path: we are entering a statement which was emitted in previous phase
- final StatementContextBase<?, ?, ?> existing = current.lookupSubstatement(childId);
+ StatementContextBase<?, ?, ?> existing = current.lookupSubstatement(childId);
+ while (existing != null && StatementSource.CONTEXT == existing.getStatementSource()) {
+ existing = existing.lookupSubstatement(childId);
+ }
if (existing != null) {
return existing;
}
import java.util.EnumMap;
import java.util.EventListener;
import java.util.Iterator;
+import java.util.Optional;
import javax.annotation.Nonnull;
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
* @param argument statement argument
* @return A new substatement
*/
- public final <CA, CD extends DeclaredStatement<CA>, CE extends EffectiveStatement<CA, CD>> StatementContextBase<CA, CD, CE>
- createSubstatement(final int offset, final StatementDefinitionContext<CA, CD, CE> def,
- final StatementSourceReference ref, final String argument) {
+ public final <CA, CD extends DeclaredStatement<CA>, CE extends EffectiveStatement<CA, CD>> StatementContextBase<CA, CD, CE> createSubstatement(
+ final int offset, final StatementDefinitionContext<CA, CD, CE> def, final StatementSourceReference ref,
+ final String argument) {
final ModelProcessingPhase inProgressPhase = getRoot().getSourceContext().getInProgressPhase();
Preconditions.checkState(inProgressPhase != ModelProcessingPhase.EFFECTIVE_MODEL,
"Declared statement cannot be added in effective phase at: %s", getStatementSourceReference());
+ final Optional<StatementContextBase<?, ?, ?>> implicitStatement = definition.beforeSubStatementCreated(this, offset, def, ref, argument);
+ if(implicitStatement.isPresent()) {
+ final StatementContextBase<?, ?, ?> presentImplicitStmt = implicitStatement.get();
+ return presentImplicitStmt.createSubstatement(offset, def, ref, argument);
+ }
+
final StatementContextBase<CA, CD, CE> ret = new SubstatementContext<>(this, def, ref, argument);
substatements = substatements.put(offset, ret);
def.onStatementAdded(ret);
import com.google.common.base.Verify;
import javax.annotation.Nonnull;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter;
public void endStatement(@Nonnull final StatementSourceReference ref) {
Preconditions.checkState(current != null);
current.endDeclared(ref, phase);
- current = current.getParentContext();
+ StatementContextBase<?, ?, ?> parentContext = current.getParentContext();
+ while (parentContext != null && StatementSource.CONTEXT == parentContext.getStatementSource()) {
+ parentContext.endDeclared(ref, phase);
+ parentContext = parentContext.getParentContext();
+ }
+ current = parentContext;
}
@Nonnull
import com.google.common.base.MoreObjects;
import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.common.base.Preconditions;
+import java.util.Optional;
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.parser.spi.meta.StatementSupport;
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.source.StatementSourceReference;
public class StatementDefinitionContext<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> {
private final StatementSupport<A, D, E> support;
return support.getPublicView();
}
+ public Optional<StatementContextBase<?, ?, ?>> beforeSubStatementCreated(final Mutable<?, ?, ?> stmt, final int offset, final StatementDefinitionContext<?, ?, ?> def, final StatementSourceReference ref,
+ final String argument) {
+ return support.beforeSubStatementCreated(stmt, offset, def, ref, argument);
+ }
+
public boolean onStatementAdded(final Mutable<A, D, E> stmt) {
support.onStatementAdded(stmt);
return false;
public StatementContextBase<A, D, E> createCopy(final QNameModule newQNameModule,
final StatementContextBase<?, ?, ?> newParent, final CopyType typeOfCopy) {
Preconditions.checkState(getCompletedPhase() == ModelProcessingPhase.EFFECTIVE_MODEL,
- "Attempted to copy statement {} which has completed phase {}", this, getCompletedPhase());
+ "Attempted to copy statement %s which has completed phase %s", this, getCompletedPhase());
final SubstatementContext<A, D, E> copy = new SubstatementContext<>(this, newQNameModule, newParent, typeOfCopy);
package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
import java.util.Collection;
+import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.parser.spi.SubstatementValidator;
import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement;
import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
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.source.ImplicitSubstatement;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementDefinitionContext;
import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ChoiceEffectiveStatementImpl;
public class ChoiceStatementImpl extends AbstractDeclaredStatement<QName>
super(context);
}
- public static class Definition
- extends
+ public static class Definition extends
AbstractStatementSupport<QName, ChoiceStatement, EffectiveStatement<QName, ChoiceStatement>> {
+ private static final StatementSupport<?, ?, ?> IMPLICIT_CASE = new CaseStatementImpl.Definition();
public Definition() {
super(YangStmtMapping.CHOICE);
}
@Override
- public void onStatementAdded(final Mutable<QName, ChoiceStatement, EffectiveStatement<QName, ChoiceStatement>> stmt) {
+ public Optional<StatementContextBase<?, ?, ?>> beforeSubStatementCreated(
+ final StmtContext.Mutable<?, ?, ?> stmt, final int offset,
+ final StatementDefinitionContext<?, ?, ?> def, final StatementSourceReference ref, final String argument) {
+
+ if (YangValidationBundles.SUPPORTED_CASE_SHORTHANDS.contains(def.getPublicView())) {
+ return Optional.of(createImplicitCase((StatementContextBase<?, ?, ?>) stmt, offset, ref, argument));
+ }
+ return Optional.empty();
+ }
+
+ @Override
+ public void onStatementAdded(
+ final Mutable<QName, ChoiceStatement, EffectiveStatement<QName, ChoiceStatement>> stmt) {
stmt.getParentContext().addToNs(ChildSchemaNodes.class, stmt.getStatementArgument(), stmt);
}
@Override
- public ChoiceStatement createDeclared(
- final StmtContext<QName, ChoiceStatement, ?> ctx) {
+ public ChoiceStatement createDeclared(final StmtContext<QName, ChoiceStatement, ?> ctx) {
return new ChoiceStatementImpl(ctx);
}
protected SubstatementValidator getSubstatementValidator() {
return SUBSTATEMENT_VALIDATOR;
}
+
+ protected StatementSupport<?, ?, ?> implictCase() {
+ return IMPLICIT_CASE;
+ }
+
+ private StatementContextBase<?, ?, ?> createImplicitCase(final StmtContext.Mutable<?, ?, ?> stmt,
+ final int offset, final StatementSourceReference ref, final String argument) {
+ final StatementDefinitionContext<?, ?, ?> def = new StatementDefinitionContext<>(implictCase());
+ return ((StatementContextBase<?, ?, ?>) stmt).createSubstatement(offset, def, ImplicitSubstatement.of(ref),
+ argument);
+ }
}
@Nonnull
import com.google.common.annotations.Beta;
import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
import org.opendaylight.yangtools.yang.parser.spi.SubstatementValidator;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.ChoiceStatementImpl;
/**
.addOptional(YangStmtMapping.WHEN)
.build();
+ private static final StatementSupport<?, ?, ?> IMPLICIT_CASE = new CaseStatementRfc7950Support();
+
+ @Override
+ protected StatementSupport<?, ?, ?> implictCase() {
+ return IMPLICIT_CASE;
+ }
+
@Override
protected SubstatementValidator getSubstatementValidator() {
return SUBSTATEMENT_VALIDATOR;
--- /dev/null
+/*
+ * Copyright (c) 2017 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.stmt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class Bug6183Test {
+ private static final String FOO_NS = "foo";
+ private static final String FOO_REV = "1970-01-01";
+
+ @Test
+ public void testYang10() throws Exception {
+ assertSchemaContext(StmtTestUtils.parseYangSources("/bugs/bug6183/yang10"));
+ }
+
+ @Test
+ public void testYang11() throws Exception {
+ assertSchemaContext(StmtTestUtils.parseYangSources("/bugs/bug6183/yang11"));
+ }
+
+ public void assertSchemaContext(final SchemaContext context) throws Exception {
+ assertNotNull(context);
+ assertEquals(3, context.getChildNodes().size());
+ assertEquals(1, context.getModules().size());
+ assertEquals(4, context.getModules().iterator().next().getAugmentations().size());
+
+ assertTrue(context.getDataChildByName(foo("before")) instanceof ContainerSchemaNode);
+ assertTrue(context.getDataChildByName(foo("after")) instanceof ContainerSchemaNode);
+
+ final DataSchemaNode dataChildByName = context.getDataChildByName(foo("my-choice"));
+ assertTrue(dataChildByName instanceof ChoiceSchemaNode);
+ final ChoiceSchemaNode myChoice = (ChoiceSchemaNode) dataChildByName;
+
+ assertEquals(4, myChoice.getCases().size());
+
+ final ChoiceCaseNode implCase = myChoice.getCaseNodeByName(foo("implicit-case-container"));
+ assertNotNull(implCase);
+ final ChoiceCaseNode declCaseOne = myChoice.getCaseNodeByName(foo("declared-case-one"));
+ assertNotNull(declCaseOne);
+ final ChoiceCaseNode secondImplCase = myChoice.getCaseNodeByName(foo("second-implicit-case-container"));
+ assertNotNull(secondImplCase);
+ final ChoiceCaseNode declCaseTwo = myChoice.getCaseNodeByName(foo("declared-case-two"));
+ assertNotNull(declCaseTwo);
+
+ assertEquals(1, declCaseOne.getChildNodes().size());
+ assertFalse(getLeafSchemaNode(declCaseOne, "leaf-in-declare-case-one").isAugmenting());
+ assertEquals(1, declCaseTwo.getChildNodes().size());
+ assertFalse(getLeafSchemaNode(declCaseTwo, "leaf-in-declare-case-two").isAugmenting());
+
+ assertEquals(2, implCase.getChildNodes().size());
+ assertTrue(getLeafSchemaNode(implCase, "leaf-after-container").isAugmenting());
+ final ContainerSchemaNode implCaseContainer = getContainerSchemaNode(implCase, "implicit-case-container");
+
+ assertEquals(3, implCaseContainer.getChildNodes().size());
+ assertTrue(getLeafSchemaNode(implCaseContainer, "leaf-inside-container").isAugmenting());
+ assertFalse(getLeafSchemaNode(implCaseContainer, "declared-leaf-in-case-container").isAugmenting());
+ final ContainerSchemaNode declContInCaseCont = getContainerSchemaNode(implCaseContainer,
+ "declared-container-in-case-container");
+
+ assertEquals(1, declContInCaseCont.getChildNodes().size());
+ assertFalse(getLeafSchemaNode(declContInCaseCont, "declared-leaf").isAugmenting());
+
+ assertEquals(2, secondImplCase.getChildNodes().size());
+ assertTrue(getLeafSchemaNode(secondImplCase, "leaf-after-second-container").isAugmenting());
+ final ContainerSchemaNode secondImplCaseContainer = getContainerSchemaNode(secondImplCase,
+ "second-implicit-case-container");
+
+ assertEquals(2, secondImplCaseContainer.getChildNodes().size());
+ assertTrue(getLeafSchemaNode(secondImplCaseContainer, "leaf-inside-second-container").isAugmenting());
+ assertFalse(getLeafSchemaNode(secondImplCaseContainer, "declared-leaf-in-second-case-container").isAugmenting());
+ }
+
+ private static ContainerSchemaNode getContainerSchemaNode(final DataNodeContainer parent, final String containerName) {
+ final DataSchemaNode dataChildByName = parent.getDataChildByName(foo(containerName));
+ assertTrue(dataChildByName instanceof ContainerSchemaNode);
+ return (ContainerSchemaNode) dataChildByName;
+ }
+
+ private static LeafSchemaNode getLeafSchemaNode(final DataNodeContainer parent, final String leafName) {
+ final DataSchemaNode dataChildByName = parent.getDataChildByName(foo(leafName));
+ assertTrue(dataChildByName instanceof LeafSchemaNode);
+ return (LeafSchemaNode) dataChildByName;
+ }
+
+ private static QName foo(final String localName) {
+ return QName.create(FOO_NS, FOO_REV, localName);
+ }
+}
--- /dev/null
+module foo {
+ namespace "foo";
+ prefix "foo";
+
+ container before {
+ }
+
+ choice my-choice {
+ container implicit-case-container {
+ container declared-container-in-case-container {
+ leaf declared-leaf {
+ type empty;
+ }
+ }
+ leaf declared-leaf-in-case-container {
+ type empty;
+ }
+ }
+ case declared-case-one {
+ leaf leaf-in-declare-case-one {
+ type empty;
+ }
+ }
+ container second-implicit-case-container {
+ leaf declared-leaf-in-second-case-container {
+ type empty;
+ }
+ }
+ case declared-case-two {
+ leaf leaf-in-declare-case-two {
+ type empty;
+ }
+ }
+ }
+
+ container after {
+ }
+
+ augment "/my-choice/implicit-case-container" {
+ leaf leaf-after-container {
+ type empty;
+ }
+ }
+
+ augment "/my-choice/implicit-case-container/implicit-case-container" {
+ leaf leaf-inside-container {
+ type empty;
+ }
+ }
+
+ augment "/my-choice/second-implicit-case-container" {
+ leaf leaf-after-second-container {
+ type empty;
+ }
+ }
+
+ augment "/my-choice/second-implicit-case-container/second-implicit-case-container" {
+ leaf leaf-inside-second-container {
+ type empty;
+ }
+ }
+}
--- /dev/null
+module foo {
+ namespace "foo";
+ prefix "foo";
+ yang-version 1.1;
+
+ container before {
+ }
+
+ choice my-choice {
+ container implicit-case-container {
+ container declared-container-in-case-container {
+ leaf declared-leaf {
+ type empty;
+ }
+ }
+ leaf declared-leaf-in-case-container {
+ type empty;
+ }
+ }
+ case declared-case-one {
+ leaf leaf-in-declare-case-one {
+ type empty;
+ }
+ }
+ container second-implicit-case-container {
+ leaf declared-leaf-in-second-case-container {
+ type empty;
+ }
+ }
+ case declared-case-two {
+ leaf leaf-in-declare-case-two {
+ type empty;
+ }
+ }
+ }
+
+ container after {
+ }
+
+ augment "/my-choice/implicit-case-container" {
+ leaf leaf-after-container {
+ type empty;
+ }
+ }
+
+ augment "/my-choice/implicit-case-container/implicit-case-container" {
+ leaf leaf-inside-container {
+ type empty;
+ }
+ }
+
+ augment "/my-choice/second-implicit-case-container" {
+ leaf leaf-after-second-container {
+ type empty;
+ }
+ }
+
+ augment "/my-choice/second-implicit-case-container/second-implicit-case-container" {
+ leaf leaf-inside-second-container {
+ type empty;
+ }
+ }
+}