import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementDefinitionContext;
/**
- *
* Support for processing concrete YANG statement.
*
+ * <p>
* This interface is intended to be implemented by developers, which want to
* introduce support of statement to parser. Consider subclassing
* {@link AbstractStatementSupport} for easier implementation of this interface.
default String internArgument(final String rawArgument) {
return rawArgument;
}
+
+ /**
+ * Returns unknown statement form of a regular yang statement supplied as
+ * parameter to the method.
+ *
+ * @param yangStmtDef
+ * statement definition of a regular yang statement
+ * @return Optional of unknown statement form of a regular yang statement or
+ * Optional.empty() if it is not supported by this statement support
+ */
+ default Optional<StatementDefinitionContext<?, ?, ?>> getUnknownStatementDefinitionOf(
+ final StatementDefinitionContext<?, ?, ?> yangStmtDef) {
+ return Optional.empty();
+ }
}
+
.add(ModelProcessingPhase.FULL_DECLARATION).add(ModelProcessingPhase.EFFECTIVE_MODEL).build();
private final Table<YangVersion, QName, StatementDefinitionContext<?, ?, ?>> definitions = HashBasedTable.create();
+ private final Map<QName, StatementDefinitionContext<?, ?, ?>> modelDefinedStmtDefs = new HashMap<>();
private final Map<Class<?>, NamespaceBehaviourWithListeners<?, ?, ?>> supportedNamespaces = new HashMap<>();
private final List<MutableStatement> mutableStatementsToSeal = new ArrayList<>();
private final Map<ModelProcessingPhase, StatementSupportBundle> supports;
return potential;
}
+ StatementDefinitionContext<?, ?, ?> getModelDefinedStatementDefinition(final QName name) {
+ return modelDefinedStmtDefs.get(name);
+ }
+
+ void putModelDefinedStatementDefinition(final QName name, final StatementDefinitionContext<?, ?, ?> def) {
+ modelDefinedStmtDefs.put(name, def);
+ }
+
private void executePhases() throws ReactorException {
for (final ModelProcessingPhase phase : PHASE_EXECUTION_ORDER) {
startPhase(phase);
import org.opendaylight.yangtools.yang.parser.spi.meta.StatementDefinitionNamespace;
import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportBundle;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToModuleContext;
import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToPrefixToModuleIdentifier;
import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToModuleIdentifier;
import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.ModelDefinedStatementDefinition;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.UnknownStatementImpl;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
StatementDefinitionContext<?, ?, ?> def = currentContext.getStatementDefinition(getRootVersion(), name);
if (def == null) {
- final StatementSupport<?, ?, ?> extension = qNameToStmtDefMap.get(name);
- if (extension != null) {
- def = new StatementDefinitionContext<>(extension);
+ def = currentContext.getModelDefinedStatementDefinition(name);
+ if (def == null) {
+ final StatementSupport<?, ?, ?> extension = qNameToStmtDefMap.get(name);
+ if (extension != null) {
+ def = new StatementDefinitionContext<>(extension);
+ currentContext.putModelDefinedStatementDefinition(name, def);
+ }
}
- } else if (current != null && current.definition().getRepresentingClass().equals(UnknownStatementImpl.class)) {
+ } else if (current != null && StmtContextUtils.isUnknownStatement(current)) {
/*
- * This code wraps statements encountered inside an extension so they do not get confused with regular
- * statements.
- *
- * FIXME: BUG-7037: re-evaluate whether this is really needed, as this is a very expensive way of making
- * this work. We really should be peeking into the extension definition to find these nodes,
- * as otherwise we are not reusing definitions nor support for these nodes.
+ * This code wraps statements encountered inside an extension so
+ * they do not get confused with regular statements.
*/
- final QName qName = Utils.qNameFromArgument(current, name.getLocalName());
- def = new StatementDefinitionContext<>(new UnknownStatementImpl.Definition(
- new ModelDefinedStatementDefinition(qName, argument != null)));
+ def = Preconditions.checkNotNull(current.definition().getAsUnknownStatementDefinition(def),
+ "Unable to create unknown statement definition of yang statement %s in unknown statement %s", def,
+ current);
}
InferenceException.throwIfNull(def, ref, "Statement %s does not have type mapping defined.", name);
public class StatementDefinitionContext<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> {
private final StatementSupport<A, D, E> support;
private final Map<String, StatementDefinitionContext<?, ?, ?>> argumentSpecificSubDefinitions;
+ private Map<StatementDefinitionContext<?,?,?>, StatementDefinitionContext<?,?,?>> unknownStmtDefsOfYangStmts;
public StatementDefinitionContext(final StatementSupport<A, D, E> support) {
this.support = Preconditions.checkNotNull(support);
return support.getArgumentName() != null;
}
+ public boolean isArgumentYinElement() {
+ return support.isArgumentYinElement();
+ }
+
public QName getStatementName() {
return support.getStatementName();
}
+ public QName getArgumentName() {
+ return support.getArgumentName();
+ }
+
@Override
public final String toString() {
return addToStringAttributes(MoreObjects.toStringHelper(this).omitNullValues()).toString();
}
@Nonnull
- public StatementDefinitionContext<?, ?, ?> getSubDefinitionSpecificForArgument(final String argument) {
+ StatementDefinitionContext<?, ?, ?> getSubDefinitionSpecificForArgument(final String argument) {
if (!hasArgumentSpecificSubDefinitions()) {
return this;
}
return potential;
}
- public boolean hasArgumentSpecificSubDefinitions() {
+ boolean hasArgumentSpecificSubDefinitions() {
return support.hasArgumentSpecificSupports();
}
String internArgument(final String rawArgument) {
return support.internArgument(rawArgument);
}
+
+ StatementDefinitionContext<?, ?, ?> getAsUnknownStatementDefinition(
+ final StatementDefinitionContext<?, ?, ?> yangStmtDef) {
+ if (unknownStmtDefsOfYangStmts == null) {
+ unknownStmtDefsOfYangStmts = new HashMap<>();
+ }
+
+ StatementDefinitionContext<?, ?, ?> ret = unknownStmtDefsOfYangStmts.get(yangStmtDef);
+ if (ret != null) {
+ return ret;
+ }
+
+ ret = support.getUnknownStatementDefinitionOf(yangStmtDef).orElse(null);
+
+ if (ret != null) {
+ unknownStmtDefsOfYangStmts.put(yangStmtDef, ret);
+ }
+ return ret;
+ }
}
this.yinElement = yinElement;
}
- @Deprecated
- public ModelDefinedStatementDefinition(final QName qname, final boolean hasArgument) {
- this(qname, hasArgument ? qname : null, false);
- }
-
@Nonnull
@Override
public QName getStatementName() {
*/
package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
+import java.util.Optional;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.UnknownStatement;
import org.opendaylight.yangtools.yang.parser.spi.SubstatementValidator;
import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementDefinitionContext;
/**
* StatementSupport for statements defined via YANG extensions. This is implemented by piggy-backing
protected SubstatementValidator getSubstatementValidator() {
return null;
}
+
+ @Override
+ public Optional<StatementDefinitionContext<?, ?, ?>> getUnknownStatementDefinitionOf(
+ final StatementDefinitionContext<?, ?, ?> yangStmtDef) {
+ return definition.getUnknownStatementDefinitionOf(yangStmtDef);
+ }
}
*/
package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
+import java.util.Optional;
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.model.api.stmt.UnknownStatement;
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.StmtContext;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementDefinitionContext;
import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.UnknownEffectiveStatementImpl;
public class UnknownStatementImpl extends AbstractDeclaredStatement<String> implements UnknownStatement<String> {
protected SubstatementValidator getSubstatementValidator() {
return null;
}
+
+ @Override
+ public Optional<StatementDefinitionContext<?, ?, ?>> getUnknownStatementDefinitionOf(
+ final StatementDefinitionContext<?, ?, ?> yangStmtDef) {
+ final QName baseQName = getStatementName();
+ return Optional.of(new StatementDefinitionContext<>(
+ new ModelDefinedStatementSupport(new ModelDefinedStatementDefinition(
+ QName.create(baseQName, yangStmtDef.getStatementName().getLocalName()),
+ yangStmtDef.hasArgument()
+ ? QName.create(baseQName, yangStmtDef.getArgumentName().getLocalName()) : null,
+ yangStmtDef.isArgumentYinElement()))));
+ }
}
@Nullable
assertEquals(expectedNodeType, info.getNodeType());
assertEquals("greeting", info.getNodeParameter());
- expectedNodeType = QName.create(qm, "description");
+ expectedNodeType = QName.create("urn:test:bug1412:ext:definitions", "2014-07-25", "description");
assertEquals(expectedNodeType, description.getNodeType());
assertEquals("say greeting", description.getNodeParameter());
assertEquals(expectedNodeType, actionPoint.getNodeType());
assertEquals("entry", actionPoint.getNodeParameter());
- expectedNodeType = QName.create(qm, "output");
+ expectedNodeType = QName.create("urn:test:bug1412:ext:definitions", "2014-07-25", "output");
assertEquals(expectedNodeType, output.getNodeType());
assertEquals("", output.getNodeParameter());
}
--- /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.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+
+public class Bug7037Test {
+ private static final String FOO_NS = "foo";
+ private static final String BAR_NS = "bar";
+ private static final String REV = "1970-01-01";
+
+ @Test
+ public void test() throws Exception {
+ final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug7037");
+ assertNotNull(context);
+
+ final List<UnknownSchemaNode> unknownSchemaNodes = context.getUnknownSchemaNodes();
+ assertEquals(1, unknownSchemaNodes.size());
+
+ final UnknownSchemaNode first = unknownSchemaNodes.iterator().next();
+ final List<UnknownSchemaNode> firstUnknownNodes = first.getUnknownSchemaNodes();
+ assertEquals(1, firstUnknownNodes.size());
+
+ final UnknownSchemaNode barExtCont = firstUnknownNodes.iterator().next();
+ assertEquals(bar("container"), barExtCont.getNodeType());
+ assertEquals(foo("bar-ext-con"), barExtCont.getQName());
+
+ final DataSchemaNode root = context.getDataChildByName(foo("root"));
+ assertTrue(root instanceof ContainerSchemaNode);
+
+ final List<UnknownSchemaNode> rootUnknownNodes = root.getUnknownSchemaNodes();
+ assertEquals(2, rootUnknownNodes.size());
+
+ final Map<QName, UnknownSchemaNode> rootUnknownNodeMap = rootUnknownNodes.stream()
+ .collect(Collectors.toMap(u -> u.getNodeType(), u -> u));
+
+ final UnknownSchemaNode barExt = rootUnknownNodeMap.get(bar("bar-ext"));
+ final List<UnknownSchemaNode> barExtUnknownNodes = barExt.getUnknownSchemaNodes();
+ assertEquals(3, barExtUnknownNodes.size());
+
+ final Iterator<UnknownSchemaNode> iterator = barExtUnknownNodes.iterator();
+ UnknownSchemaNode barExtCont2 = null;
+ while(iterator.hasNext()) {
+ final UnknownSchemaNode next = iterator.next();
+ if(bar("container").equals(next.getNodeType())) {
+ barExtCont2 = next;
+ break;
+ }
+ }
+ assertNotNull(barExtCont2);
+ assertEquals(foo("bar-ext-con-2"), barExtCont2.getQName());
+
+ final UnknownSchemaNode fooExt = rootUnknownNodeMap.get(foo("foo-ext"));
+ final List<UnknownSchemaNode> fooUnknownNodes = fooExt.getUnknownSchemaNodes();
+ assertEquals(1, fooUnknownNodes.size());
+
+ final UnknownSchemaNode fooExtCont = fooUnknownNodes.iterator().next();
+ assertEquals(foo("container"), fooExtCont.getNodeType());
+ assertEquals(foo("foo-ext-con"), fooExtCont.getQName());
+ }
+
+ private static QName foo(final String localName) {
+ return QName.create(FOO_NS, REV, localName);
+ }
+
+ private static QName bar(final String localName) {
+ return QName.create(BAR_NS, REV, localName);
+ }
+}
--- /dev/null
+module bar {
+ namespace bar;
+ prefix bar;
+
+ extension bar-ext {
+ argument arg;
+ }
+
+ extension bar-ext-2 {
+ }
+}
--- /dev/null
+module foo {
+ namespace foo;
+ prefix foo;
+
+ import bar { prefix bar; revision-date 1970-01-01; }
+
+ extension foo-ext {
+ argument arg;
+ }
+
+ bar:bar-ext "first" {
+ container bar-ext-con {
+ }
+ }
+
+ container root {
+ bar:bar-ext "bar" {
+ container bar-ext-con-2 {
+ }
+ bar:bar-ext "sub-bar" {
+ container bar-ext-con-3 {
+ }
+ }
+ bar:bar-ext-2 {
+ container bar-ext-2-con {
+ }
+ }
+ }
+ foo:foo-ext "foo" {
+ container foo-ext-con;
+ }
+ }
+}