Yang parser fails when target node of uses-augment is an unknown node. It is not
quite clear whether such yang model is valid according to RFC6020 or not, but
yang parser failure causes lots of trouble, because such augment is used widely
in some yang models. So this patch prevents failure of yang parser and rather
introduces a warning and augmentation is not performed, when target node is
an unknown node.
Change-Id: I7f1c5d7b3ef0898ca098466702d7cb1ad7a0f30f
Signed-off-by: Peter Kajsa <pkajsa@cisco.com>
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
import java.util.Set;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
Preconditions.checkNotNull(statementParserMode, "Statement parser mode must not be null.");
this.enabledSemanticVersions = statementParserMode == StatementParserMode.SEMVER_MODE;
Preconditions.checkNotNull(statementParserMode, "Statement parser mode must not be null.");
this.enabledSemanticVersions = statementParserMode == StatementParserMode.SEMVER_MODE;
- for (Entry<ValidationBundleType, Collection<?>> validationBundle : supportedValidation.entrySet()) {
+ for (final Entry<ValidationBundleType, Collection<?>> validationBundle : supportedValidation.entrySet()) {
addToNs(ValidationBundlesNamespace.class, validationBundle.getKey(), validationBundle.getValue());
}
addToNs(ValidationBundlesNamespace.class, validationBundle.getKey(), validationBundle.getValue());
}
final Class<N> type) {
NamespaceBehaviourWithListeners<?, ?, ?> potential = supportedNamespaces.get(type);
if (potential == null) {
final Class<N> type) {
NamespaceBehaviourWithListeners<?, ?, ?> potential = supportedNamespaces.get(type);
if (potential == null) {
- NamespaceBehaviour<K, V, N> potentialRaw = supports.get(currentPhase).getNamespaceBehaviour(type);
+ final NamespaceBehaviour<K, V, N> potentialRaw = supports.get(currentPhase).getNamespaceBehaviour(type);
if (potentialRaw != null) {
potential = createNamespaceContext(potentialRaw);
supportedNamespaces.put(type, potential);
if (potentialRaw != null) {
potential = createNamespaceContext(potentialRaw);
supportedNamespaces.put(type, potential);
private <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviourWithListeners<K, V, N> createNamespaceContext(
final NamespaceBehaviour<K, V, N> potentialRaw) {
if (potentialRaw instanceof DerivedNamespaceBehaviour) {
private <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviourWithListeners<K, V, N> createNamespaceContext(
final NamespaceBehaviour<K, V, N> potentialRaw) {
if (potentialRaw instanceof DerivedNamespaceBehaviour) {
- VirtualNamespaceContext derivedContext = new VirtualNamespaceContext(
+ final VirtualNamespaceContext derivedContext = new VirtualNamespaceContext(
(DerivedNamespaceBehaviour) potentialRaw);
getNamespaceBehaviour(((DerivedNamespaceBehaviour) potentialRaw).getDerivedFrom()).addDerivedNamespace(
derivedContext);
(DerivedNamespaceBehaviour) potentialRaw);
getNamespaceBehaviour(((DerivedNamespaceBehaviour) potentialRaw).getDerivedFrom()).addDerivedNamespace(
derivedContext);
public StatementDefinitionContext<?, ?, ?> getStatementDefinition(final QName name) {
StatementDefinitionContext<?, ?, ?> potential = definitions.get(name);
if (potential == null) {
public StatementDefinitionContext<?, ?, ?> getStatementDefinition(final QName name) {
StatementDefinitionContext<?, ?, ?> potential = definitions.get(name);
if (potential == null) {
- StatementSupport<?, ?, ?> potentialRaw = supports.get(currentPhase).getStatementDefinition(name);
+ final StatementSupport<?, ?, ?> potentialRaw = supports.get(currentPhase).getStatementDefinition(name);
if (potentialRaw != null) {
potential = new StatementDefinitionContext<>(potentialRaw);
definitions.put(name, potential);
if (potentialRaw != null) {
potential = new StatementDefinitionContext<>(potentialRaw);
definitions.put(name, potential);
}
public EffectiveModelContext build() throws SourceException, ReactorException {
}
public EffectiveModelContext build() throws SourceException, ReactorException {
- for (ModelProcessingPhase phase : PHASE_EXECUTION_ORDER) {
+ for (final ModelProcessingPhase phase : PHASE_EXECUTION_ORDER) {
startPhase(phase);
loadPhaseStatements();
completePhaseActions();
startPhase(phase);
loadPhaseStatements();
completePhaseActions();
private EffectiveModelContext transform() {
Preconditions.checkState(finishedPhase == ModelProcessingPhase.EFFECTIVE_MODEL);
private EffectiveModelContext transform() {
Preconditions.checkState(finishedPhase == ModelProcessingPhase.EFFECTIVE_MODEL);
- List<DeclaredStatement<?>> rootStatements = new ArrayList<>(sources.size());
- for (SourceSpecificContext source : sources) {
+ final List<DeclaredStatement<?>> rootStatements = new ArrayList<>(sources.size());
+ for (final SourceSpecificContext source : sources) {
rootStatements.add(source.getRoot().buildDeclared());
}
return new EffectiveModelContext(rootStatements);
}
public EffectiveSchemaContext buildEffective() throws ReactorException {
rootStatements.add(source.getRoot().buildDeclared());
}
return new EffectiveModelContext(rootStatements);
}
public EffectiveSchemaContext buildEffective() throws ReactorException {
- for (ModelProcessingPhase phase : PHASE_EXECUTION_ORDER) {
+ for (final ModelProcessingPhase phase : PHASE_EXECUTION_ORDER) {
startPhase(phase);
loadPhaseStatements();
completePhaseActions();
startPhase(phase);
loadPhaseStatements();
completePhaseActions();
private EffectiveSchemaContext transformEffective() throws ReactorException {
Preconditions.checkState(finishedPhase == ModelProcessingPhase.EFFECTIVE_MODEL);
private EffectiveSchemaContext transformEffective() throws ReactorException {
Preconditions.checkState(finishedPhase == ModelProcessingPhase.EFFECTIVE_MODEL);
- List<DeclaredStatement<?>> rootStatements = new ArrayList<>(sources.size());
- List<EffectiveStatement<?, ?>> rootEffectiveStatements = new ArrayList<>(sources.size());
+ final List<DeclaredStatement<?>> rootStatements = new ArrayList<>(sources.size());
+ final List<EffectiveStatement<?, ?>> rootEffectiveStatements = new ArrayList<>(sources.size());
SourceIdentifier sourceId = null;
try {
SourceIdentifier sourceId = null;
try {
- for (SourceSpecificContext source : sources) {
+ for (final SourceSpecificContext source : sources) {
final RootStatementContext<?, ?, ?> root = source.getRoot();
sourceId = Utils.createSourceIdentifier(root);
rootStatements.add(root.buildDeclared());
rootEffectiveStatements.add(root.buildEffective());
}
final RootStatementContext<?, ?, ?> root = source.getRoot();
sourceId = Utils.createSourceIdentifier(root);
rootStatements.add(root.buildDeclared());
rootEffectiveStatements.add(root.buildEffective());
}
- } catch (SourceException ex) {
+ } catch (final SourceException ex) {
throw new SomeModifiersUnresolvedException(currentPhase, sourceId, ex);
} finally {
RecursiveObjectLeaker.cleanup();
throw new SomeModifiersUnresolvedException(currentPhase, sourceId, ex);
} finally {
RecursiveObjectLeaker.cleanup();
private void startPhase(final ModelProcessingPhase phase) {
Preconditions.checkState(Objects.equals(finishedPhase, phase.getPreviousPhase()));
private void startPhase(final ModelProcessingPhase phase) {
Preconditions.checkState(Objects.equals(finishedPhase, phase.getPreviousPhase()));
- for (SourceSpecificContext source : sources) {
+ for (final SourceSpecificContext source : sources) {
source.startPhase(phase);
}
currentPhase = phase;
source.startPhase(phase);
}
currentPhase = phase;
private void loadPhaseStatements() throws ReactorException {
Preconditions.checkState(currentPhase != null);
private void loadPhaseStatements() throws ReactorException {
Preconditions.checkState(currentPhase != null);
- for (SourceSpecificContext source : sources) {
+ for (final SourceSpecificContext source : sources) {
try {
source.loadStatements();
try {
source.loadStatements();
- } catch (SourceException ex) {
+ } catch (final SourceException ex) {
final SourceIdentifier sourceId = Utils.createSourceIdentifier(source.getRoot());
throw new SomeModifiersUnresolvedException(currentPhase, sourceId, ex);
}
final SourceIdentifier sourceId = Utils.createSourceIdentifier(source.getRoot());
throw new SomeModifiersUnresolvedException(currentPhase, sourceId, ex);
}
private SomeModifiersUnresolvedException addSourceExceptions(final List<SourceSpecificContext> sourcesToProgress) {
boolean addedCause = false;
SomeModifiersUnresolvedException buildFailure = null;
private SomeModifiersUnresolvedException addSourceExceptions(final List<SourceSpecificContext> sourcesToProgress) {
boolean addedCause = false;
SomeModifiersUnresolvedException buildFailure = null;
- for (SourceSpecificContext failedSource : sourcesToProgress) {
- final SourceException sourceEx = failedSource.failModifiers(currentPhase);
+ for (final SourceSpecificContext failedSource : sourcesToProgress) {
+ final Optional<SourceException> optSourceEx = failedSource.failModifiers(currentPhase);
+ if (!optSourceEx.isPresent()) {
+ continue;
+ }
+ final SourceException sourceEx = optSourceEx.get();
// Workaround for broken logging implementations which ignore
// suppressed exceptions
// Workaround for broken logging implementations which ignore
// suppressed exceptions
- Throwable cause = sourceEx.getCause() != null ? sourceEx.getCause() : sourceEx;
+ final Throwable cause = sourceEx.getCause() != null ? sourceEx.getCause() : sourceEx;
if (LOG.isDebugEnabled()) {
LOG.error("Failed to parse YANG from source {}", failedSource, sourceEx);
} else {
if (LOG.isDebugEnabled()) {
LOG.error("Failed to parse YANG from source {}", failedSource, sourceEx);
} else {
LOG.error("{} additional errors reported:", suppressed.length);
int i = 1;
LOG.error("{} additional errors reported:", suppressed.length);
int i = 1;
- for (Throwable t : suppressed) {
+ for (final Throwable t : suppressed) {
// FIXME: this should be configured in the appender, really
if (LOG.isDebugEnabled()) {
LOG.error("Error {}: {}", i, t.getMessage(), t);
// FIXME: this should be configured in the appender, really
if (LOG.isDebugEnabled()) {
LOG.error("Error {}: {}", i, t.getMessage(), t);
private void completePhaseActions() throws ReactorException {
Preconditions.checkState(currentPhase != null);
private void completePhaseActions() throws ReactorException {
Preconditions.checkState(currentPhase != null);
- List<SourceSpecificContext> sourcesToProgress = Lists.newArrayList(sources);
+ final List<SourceSpecificContext> sourcesToProgress = Lists.newArrayList(sources);
SourceIdentifier sourceId = null;
try {
boolean progressing = true;
while (progressing) {
// We reset progressing to false.
progressing = false;
SourceIdentifier sourceId = null;
try {
boolean progressing = true;
while (progressing) {
// We reset progressing to false.
progressing = false;
- Iterator<SourceSpecificContext> currentSource = sourcesToProgress.iterator();
+ final Iterator<SourceSpecificContext> currentSource = sourcesToProgress.iterator();
while (currentSource.hasNext()) {
while (currentSource.hasNext()) {
- SourceSpecificContext nextSourceCtx = currentSource.next();
+ final SourceSpecificContext nextSourceCtx = currentSource.next();
sourceId = Utils.createSourceIdentifier(nextSourceCtx.getRoot());
sourceId = Utils.createSourceIdentifier(nextSourceCtx.getRoot());
- PhaseCompletionProgress sourceProgress = nextSourceCtx.tryToCompletePhase(currentPhase);
+ final PhaseCompletionProgress sourceProgress = nextSourceCtx.tryToCompletePhase(currentPhase);
switch (sourceProgress) {
case FINISHED:
currentSource.remove();
switch (sourceProgress) {
case FINISHED:
currentSource.remove();
- } catch (SourceException e) {
+ } catch (final SourceException e) {
throw new SomeModifiersUnresolvedException(currentPhase, sourceId, e);
}
if (!sourcesToProgress.isEmpty()) {
final SomeModifiersUnresolvedException buildFailure = addSourceExceptions(sourcesToProgress);
throw new SomeModifiersUnresolvedException(currentPhase, sourceId, e);
}
if (!sourcesToProgress.isEmpty()) {
final SomeModifiersUnresolvedException buildFailure = addSourceExceptions(sourcesToProgress);
+ if (buildFailure != null) {
+ throw buildFailure;
+ }
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.Optional;
import javax.annotation.Nullable;
import org.opendaylight.yangtools.concepts.Mutable;
import org.opendaylight.yangtools.yang.common.QName;
import javax.annotation.Nullable;
import org.opendaylight.yangtools.concepts.Mutable;
import org.opendaylight.yangtools.yang.common.QName;
- SourceException failModifiers(final ModelProcessingPhase identifier) {
+ Optional<SourceException> failModifiers(final ModelProcessingPhase identifier) {
final List<SourceException> exceptions = new ArrayList<>();
for (final ModifierImpl mod : modifiers.get(identifier)) {
try {
final List<SourceException> exceptions = new ArrayList<>();
for (final ModifierImpl mod : modifiers.get(identifier)) {
try {
- final String message = String.format("Yang model processing phase %s failed", identifier);
if (exceptions.isEmpty()) {
if (exceptions.isEmpty()) {
- return new InferenceException(message, root.getStatementSourceReference());
+ return Optional.empty();
+ final String message = String.format("Yang model processing phase %s failed", identifier);
final InferenceException e = new InferenceException(message, root.getStatementSourceReference(),
exceptions.get(0));
final Iterator<SourceException> it = exceptions.listIterator(1);
final InferenceException e = new InferenceException(message, root.getStatementSourceReference(),
exceptions.get(0));
final Iterator<SourceException> it = exceptions.listIterator(1);
e.addSuppressed(it.next());
}
e.addSuppressed(it.next());
}
}
void loadStatements() throws SourceException {
}
void loadStatements() throws SourceException {
AugmentUtils.copyFromSourceToTarget(augmentSourceCtx, augmentTargetCtx);
augmentTargetCtx.addEffectiveSubstatement(augmentSourceCtx);
updateAugmentOrder(augmentSourceCtx);
AugmentUtils.copyFromSourceToTarget(augmentSourceCtx, augmentTargetCtx);
augmentTargetCtx.addEffectiveSubstatement(augmentSourceCtx);
updateAugmentOrder(augmentSourceCtx);
- } catch (SourceException e) {
+ } catch (final SourceException e) {
LOG.debug("Failed to add augmentation {} defined at {}",
augmentTargetCtx.getStatementSourceReference(),
augmentSourceCtx.getStatementSourceReference(), e);
LOG.debug("Failed to add augmentation {} defined at {}",
augmentTargetCtx.getStatementSourceReference(),
augmentSourceCtx.getStatementSourceReference(), e);
@Override
public void prerequisiteFailed(final Collection<? extends ModelActionBuilder.Prerequisite<?>> failed) {
@Override
public void prerequisiteFailed(final Collection<? extends ModelActionBuilder.Prerequisite<?>> failed) {
+ /*
+ * Do not fail, if it is an uses-augment to an unknown node.
+ */
+ if (Rfc6020Mapping.USES == augmentNode.getParentContext().getPublicDefinition()) {
+ final StatementContextBase<?, ?, ?> targetNode = Utils.findNode(getSearchRoot(augmentNode),
+ augmentNode.getStatementArgument());
+ if (Utils.isUnknownNode(targetNode)) {
+ augmentNode.setIsSupportedToBuildEffective(false);
+ LOG.warn(
+ "Uses-augment to unknown node {}. Augmentation has not been performed. At line: {}",
+ augmentNode.getStatementArgument(), augmentNode.getStatementSourceReference());
+ return;
+ }
+ }
+
throw new InferenceException(augmentNode.getStatementSourceReference(),
throw new InferenceException(augmentNode.getStatementSourceReference(),
- "Augment target '%s' not found", augmentNode.getStatementArgument());
+ "Augment target '%s' not found", augmentNode.getStatementArgument());
}
});
}
private static Mutable<?, ?, ?> getSearchRoot(final Mutable<?, ?, ?> augmentContext) {
}
});
}
private static Mutable<?, ?, ?> getSearchRoot(final Mutable<?, ?, ?> augmentContext) {
- Mutable<?, ?, ?> parent = augmentContext.getParentContext();
+ final Mutable<?, ?, ?> parent = augmentContext.getParentContext();
// Augment is in uses - we need to augment instantiated nodes in parent.
// Augment is in uses - we need to augment instantiated nodes in parent.
- if (Rfc6020Mapping.USES.equals(parent.getPublicDefinition())) {
+ if (Rfc6020Mapping.USES == parent.getPublicDefinition()) {
return parent.getParentContext();
}
return parent;
return parent.getParentContext();
}
return parent;
}
public static boolean isUnknownNode(final StmtContext<?, ?, ?> stmtCtx) {
}
public static boolean isUnknownNode(final StmtContext<?, ?, ?> stmtCtx) {
- return stmtCtx.getPublicDefinition().getDeclaredRepresentationClass()
+ return stmtCtx != null && stmtCtx.getPublicDefinition().getDeclaredRepresentationClass()
.isAssignableFrom(UnknownStatementImpl.class);
}
.isAssignableFrom(UnknownStatementImpl.class);
}
- public static SourceIdentifier createSourceIdentifier(RootStatementContext<?, ?, ?> root) {
+ public static SourceIdentifier createSourceIdentifier(final RootStatementContext<?, ?, ?> root) {
final QNameModule qNameModule = root.getFromNamespace(ModuleCtxToModuleQName.class, root);
if (qNameModule != null) {
// creates SourceIdentifier for a module
final QNameModule qNameModule = root.getFromNamespace(ModuleCtxToModuleQName.class, root);
if (qNameModule != null) {
// creates SourceIdentifier for a module
import java.net.URISyntaxException;
import java.util.Set;
import java.net.URISyntaxException;
import java.util.Set;
-import org.junit.Ignore;
import org.junit.Test;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
import org.junit.Test;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
public void testCorrectPathIntoUnsupportedTarget() throws URISyntaxException, SourceException, ReactorException {
try {
public void testCorrectPathIntoUnsupportedTarget() throws URISyntaxException, SourceException, ReactorException {
try {
container my-container {
uses my-grouping {
container my-container {
uses my-grouping {
- augment "my-extension-name/input/a" {
+ augment "my-extension-name-a/input" {
leaf-list my-leaf-list {
type string;
}
leaf-list my-leaf-list {
type string;
}