From 920c8711850b01440ecf9967744e970d14fb6326 Mon Sep 17 00:00:00 2001 From: Peter Kajsa Date: Tue, 6 Sep 2016 14:35:02 +0200 Subject: [PATCH] Bug 6551: Support for third-party Yang extensions implementation Minor changes in yang statement parser in order to allow implementation of custom inference pipeline. - implementation of CustomStatementParserBuilder, which provides construction of custom statement parser in user-friendly way. - example and unit test of third-party extension plugin. Change-Id: I0cdf0e28bd69af4cb41328be6e6a647df58f4fd9 Signed-off-by: Peter Kajsa --- .../spi/meta/StatementSupportBundle.java | 49 ++++--- .../ValidationBundlesNamespace.java | 2 +- .../reactor/CustomStatementParserBuilder.java | 123 ++++++++++++++++++ .../parser/stmt/rfc6020/ChildSchemaNodes.java | 2 +- .../SchemaNodeIdentifierBuildNamespace.java | 18 +-- .../stmt/rfc6020/URIStringToImpPrefix.java | 4 +- .../stmt/rfc6020/YangInferencePipeline.java | 15 ++- .../plugin/CustomInferencePipeline.java | 27 ++++ ...dPartyExtensionEffectiveStatementImpl.java | 73 +++++++++++ .../plugin/ThirdPartyExtensionPluginTest.java | 54 ++++++++ .../ThirdPartyExtensionStatementImpl.java | 59 +++++++++ .../plugin/ThirdPartyExtensionsMapping.java | 88 +++++++++++++ .../plugin/ThirdPartyNamespace.java | 20 +++ .../src/test/resources/plugin-test/foo.yang | 15 +++ 14 files changed, 515 insertions(+), 34 deletions(-) create mode 100644 yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/CustomStatementParserBuilder.java create mode 100644 yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/CustomInferencePipeline.java create mode 100644 yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionEffectiveStatementImpl.java create mode 100644 yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionPluginTest.java create mode 100644 yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionStatementImpl.java create mode 100644 yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionsMapping.java create mode 100644 yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyNamespace.java create mode 100644 yang/yang-parser-impl/src/test/resources/plugin-test/foo.yang diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupportBundle.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupportBundle.java index 08e723ecce..1f008e723d 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupportBundle.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupportBundle.java @@ -23,9 +23,9 @@ public final class StatementSupportBundle implements Immutable,NamespaceBehaviou private final ImmutableMap> definitions; private final ImmutableMap, NamespaceBehaviour> namespaceDefinitions; - private StatementSupportBundle(StatementSupportBundle parent, - ImmutableMap> statements, - ImmutableMap, NamespaceBehaviour> namespaces) { + private StatementSupportBundle(final StatementSupportBundle parent, + final ImmutableMap> statements, + final ImmutableMap, NamespaceBehaviour> namespaces) { this.parent = parent; this.definitions = statements; this.namespaceDefinitions = namespaces; @@ -35,18 +35,22 @@ public final class StatementSupportBundle implements Immutable,NamespaceBehaviou return definitions; } + public ImmutableMap, NamespaceBehaviour> getNamespaceDefinitions() { + return namespaceDefinitions; + } + public static Builder builder() { return new Builder(EMPTY); } - public static Builder derivedFrom(StatementSupportBundle parent) { + public static Builder derivedFrom(final StatementSupportBundle parent) { return new Builder(parent); } @Override - public > NamespaceBehaviour getNamespaceBehaviour(Class namespace) + public > NamespaceBehaviour getNamespaceBehaviour(final Class namespace) throws NamespaceNotAvailableException { - NamespaceBehaviour potential = namespaceDefinitions.get(namespace); + final NamespaceBehaviour potential = namespaceDefinitions.get(namespace); if (potential != null) { Preconditions.checkState(namespace.equals(potential.getIdentifier())); @@ -62,7 +66,7 @@ public final class StatementSupportBundle implements Immutable,NamespaceBehaviou return null; } - public > boolean hasNamespaceBehaviour(Class namespace) { + public > boolean hasNamespaceBehaviour(final Class namespace) { if (namespaceDefinitions.containsKey(namespace)) { return true; } @@ -72,8 +76,8 @@ public final class StatementSupportBundle implements Immutable,NamespaceBehaviou return false; } - public StatementSupport getStatementDefinition(QName stmtName) { - StatementSupport potential = definitions.get(stmtName); + public StatementSupport getStatementDefinition(final QName stmtName) { + final StatementSupport potential = definitions.get(stmtName); if (potential != null) { return potential; } @@ -85,31 +89,38 @@ public final class StatementSupportBundle implements Immutable,NamespaceBehaviou public static class Builder implements org.opendaylight.yangtools.concepts.Builder { - private final StatementSupportBundle parent; - private final Map> statements = new HashMap<>(); + private StatementSupportBundle parent; + private final Map> statements = new HashMap<>(); private final Map, NamespaceBehaviour> namespaces = new HashMap<>(); - Builder(StatementSupportBundle parent) { + Builder(final StatementSupportBundle parent) { this.parent = parent; } - public Builder addSupport(StatementSupport definition) { - QName identifier = definition.getStatementName(); - Preconditions.checkState(!statements.containsKey(identifier), "Statement %s already defined.",identifier); - Preconditions.checkState(parent.getStatementDefinition(identifier) == null, "Statement %s already defined.",identifier); + public Builder addSupport(final StatementSupport definition) { + final QName identifier = definition.getStatementName(); + Preconditions.checkState(!statements.containsKey(identifier), "Statement %s already defined.", identifier); + Preconditions.checkState(parent.getStatementDefinition(identifier) == null, + "Statement %s already defined.", identifier); statements.put(identifier, definition); return this; } - public > Builder addSupport(NamespaceBehaviour namespaceSupport) { - Class identifier = namespaceSupport.getIdentifier(); + public > Builder addSupport( + final NamespaceBehaviour namespaceSupport) { + final Class identifier = namespaceSupport.getIdentifier(); Preconditions.checkState(!namespaces.containsKey(identifier)); Preconditions.checkState(!parent.hasNamespaceBehaviour(identifier)); namespaces.put(identifier, namespaceSupport); return this; } - @Override + public Builder setParent(final StatementSupportBundle parent) { + this.parent = parent; + return this; + } + + @Override public StatementSupportBundle build() { return new StatementSupportBundle(parent, ImmutableMap.copyOf(statements), ImmutableMap.copyOf(namespaces)); } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/validation/ValidationBundlesNamespace.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/validation/ValidationBundlesNamespace.java index b58d750f4a..8deb87e30b 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/validation/ValidationBundlesNamespace.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/validation/ValidationBundlesNamespace.java @@ -18,7 +18,7 @@ import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; public interface ValidationBundlesNamespace extends IdentifierNamespace> { - enum ValidationBundleType { + public enum ValidationBundleType { /** * whether a node is suitable refine substatement */ diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/CustomStatementParserBuilder.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/CustomStatementParserBuilder.java new file mode 100644 index 0000000000..7c648e46a9 --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/CustomStatementParserBuilder.java @@ -0,0 +1,123 @@ +/* + * 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.collect.ImmutableMap; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; +import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase; +import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour; +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.validation.ValidationBundlesNamespace.ValidationBundleType; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor.Builder; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline; + +public class CustomStatementParserBuilder { + private final Map reactorSupportBundles = ImmutableMap + . builder() + .put(ModelProcessingPhase.INIT, StatementSupportBundle.builder()) + .put(ModelProcessingPhase.SOURCE_PRE_LINKAGE, StatementSupportBundle.builder()) + .put(ModelProcessingPhase.SOURCE_LINKAGE, StatementSupportBundle.builder()) + .put(ModelProcessingPhase.STATEMENT_DEFINITION, StatementSupportBundle.builder()) + .put(ModelProcessingPhase.FULL_DECLARATION, StatementSupportBundle.builder()) + .put(ModelProcessingPhase.EFFECTIVE_MODEL, StatementSupportBundle.builder()).build(); + private final Map> reactorValidationBundles = new HashMap<>(); + + public CustomStatementParserBuilder addStatementSupport(final ModelProcessingPhase phase, + final StatementSupport stmtSupport) { + reactorSupportBundles.get(phase).addSupport(stmtSupport); + return this; + } + + public CustomStatementParserBuilder addNamespaceSupport(final ModelProcessingPhase phase, + final NamespaceBehaviour namespaceSupport) { + reactorSupportBundles.get(phase).addSupport(namespaceSupport); + return this; + } + + public CustomStatementParserBuilder addDefaultRFC6020Bundles() { + addRFC6020SupportBundles(); + addRFC6020ValidationBundles(); + return this; + } + + private void addRFC6020ValidationBundles() { + reactorValidationBundles.putAll(YangInferencePipeline.RFC6020_VALIDATION_BUNDLE); + } + + private void addRFC6020SupportBundles() { + for (final Entry entry : YangInferencePipeline.RFC6020_BUNDLES + .entrySet()) { + addAllSupports(entry.getKey(), entry.getValue()); + } + } + + public CustomStatementParserBuilder addValidationBundle(final ValidationBundleType validationBundleType, + final Collection validationBundle) { + reactorValidationBundles.put(validationBundleType, validationBundle); + return this; + } + + public CustomStatementParserBuilder addAllSupports(final ModelProcessingPhase phase, + final StatementSupportBundle stmtSupportBundle) { + addAllStatementSupports(phase, stmtSupportBundle.getDefinitions().values()); + addAllNamespaceSupports(phase, stmtSupportBundle.getNamespaceDefinitions().values()); + return this; + } + + public CustomStatementParserBuilder addAllNamespaceSupports(final ModelProcessingPhase phase, + final Collection> namespaceSupports) { + final StatementSupportBundle.Builder stmtBundleBuilder = reactorSupportBundles.get(phase); + for (final NamespaceBehaviour namespaceSupport : namespaceSupports) { + stmtBundleBuilder.addSupport(namespaceSupport); + } + return this; + } + + public CustomStatementParserBuilder addAllStatementSupports(final ModelProcessingPhase phase, + final Collection> statementSupports) { + final StatementSupportBundle.Builder stmtBundleBuilder = reactorSupportBundles.get(phase); + for (final StatementSupport statementSupport : statementSupports) { + stmtBundleBuilder.addSupport(statementSupport); + } + return this; + } + + public CrossSourceStatementReactor build() { + final StatementSupportBundle initBundle = reactorSupportBundles.get(ModelProcessingPhase.INIT).build(); + final StatementSupportBundle preLinkageBundle = reactorSupportBundles + .get(ModelProcessingPhase.SOURCE_PRE_LINKAGE).setParent(initBundle).build(); + final StatementSupportBundle linkageBundle = reactorSupportBundles.get(ModelProcessingPhase.SOURCE_LINKAGE) + .setParent(preLinkageBundle).build(); + final StatementSupportBundle stmtDefBundle = reactorSupportBundles + .get(ModelProcessingPhase.STATEMENT_DEFINITION).setParent(linkageBundle).build(); + final StatementSupportBundle fullDeclBundle = reactorSupportBundles.get(ModelProcessingPhase.FULL_DECLARATION) + .setParent(stmtDefBundle).build(); + final StatementSupportBundle effectiveBundle = reactorSupportBundles.get(ModelProcessingPhase.EFFECTIVE_MODEL) + .setParent(fullDeclBundle).build(); + + final Builder reactorBuilder = CrossSourceStatementReactor.builder() + .setBundle(ModelProcessingPhase.INIT, initBundle) + .setBundle(ModelProcessingPhase.SOURCE_PRE_LINKAGE, preLinkageBundle) + .setBundle(ModelProcessingPhase.SOURCE_LINKAGE, linkageBundle) + .setBundle(ModelProcessingPhase.STATEMENT_DEFINITION, stmtDefBundle) + .setBundle(ModelProcessingPhase.FULL_DECLARATION, fullDeclBundle) + .setBundle(ModelProcessingPhase.EFFECTIVE_MODEL, effectiveBundle); + + for (final Entry> entry : reactorValidationBundles + .entrySet()) { + reactorBuilder.setValidationBundle(entry.getKey(), entry.getValue()); + } + + return reactorBuilder.build(); + } +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ChildSchemaNodes.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ChildSchemaNodes.java index cf5450afad..344af3b6e6 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ChildSchemaNodes.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ChildSchemaNodes.java @@ -25,7 +25,7 @@ public class ChildSchemaNodes,E extends Effec extends NamespaceBehaviour, ChildSchemaNodes> implements StatementNamespace{ - protected ChildSchemaNodes() { + public ChildSchemaNodes() { super((Class) ChildSchemaNodes.class); } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/SchemaNodeIdentifierBuildNamespace.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/SchemaNodeIdentifierBuildNamespace.java index 40d84cee4c..c4c3316f86 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/SchemaNodeIdentifierBuildNamespace.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/SchemaNodeIdentifierBuildNamespace.java @@ -21,24 +21,24 @@ 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; -class SchemaNodeIdentifierBuildNamespace extends +public class SchemaNodeIdentifierBuildNamespace extends DerivedNamespaceBehaviour>, QName, SchemaNodeIdentifierBuildNamespace, ChildSchemaNodes> implements IdentifierNamespace>> { @SuppressWarnings({"unchecked", "rawtypes"}) - protected SchemaNodeIdentifierBuildNamespace() { + public SchemaNodeIdentifierBuildNamespace() { super(SchemaNodeIdentifierBuildNamespace.class, (Class) ChildSchemaNodes.class); } @Override public StmtContext.Mutable> get( - SchemaNodeIdentifier key) { + final SchemaNodeIdentifier key) { throw new UnsupportedOperationException("Direct access to namespace is not supported"); } @SuppressWarnings("unchecked") @Override - public StmtContext.Mutable> getFrom(NamespaceStorageNode storage, SchemaNodeIdentifier key) { + public StmtContext.Mutable> getFrom(final NamespaceStorageNode storage, final SchemaNodeIdentifier key) { final NamespaceStorageNode lookupStartStorage; if (key.isAbsolute() || storage.getStorageNodeType() == StorageNodeType.ROOT_STATEMENT_LOCAL) { @@ -46,7 +46,7 @@ class SchemaNodeIdentifierBuildNamespace extends } else { lookupStartStorage = storage; } - Iterator iterator = key.getPathFromRoot().iterator(); + final Iterator iterator = key.getPathFromRoot().iterator(); if (!iterator.hasNext()) { if (lookupStartStorage instanceof StmtContext) { return (StmtContext.Mutable>) lookupStartStorage; @@ -62,7 +62,7 @@ class SchemaNodeIdentifierBuildNamespace extends } while (current != null && iterator.hasNext()) { nextPath = iterator.next(); - StmtContext.Mutable> nextNodeCtx = (StmtContext.Mutable>) current + final StmtContext.Mutable> nextNodeCtx = (StmtContext.Mutable>) current .getFromNamespace(ChildSchemaNodes.class, nextPath); if (nextNodeCtx == null) { return tryToFindUnknownStatement(nextPath.getLocalName(), current); @@ -76,9 +76,9 @@ class SchemaNodeIdentifierBuildNamespace extends @SuppressWarnings({"unchecked", "rawtypes"}) private Mutable> tryToFindUnknownStatement(final String localName, final Mutable> current) { - Collection> unknownSubstatements = (Collection)StmtContextUtils.findAllSubstatements(current, + final Collection> unknownSubstatements = (Collection)StmtContextUtils.findAllSubstatements(current, UnknownStatement.class); - for (StmtContext unknownSubstatement : unknownSubstatements) { + for (final StmtContext unknownSubstatement : unknownSubstatements) { if (localName.equals(unknownSubstatement.rawStatementArgument())) { return (Mutable>) unknownSubstatement; } @@ -87,7 +87,7 @@ class SchemaNodeIdentifierBuildNamespace extends } @Override - public QName getSignificantKey(SchemaNodeIdentifier key) { + public QName getSignificantKey(final SchemaNodeIdentifier key) { return key.getLastComponent(); } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/URIStringToImpPrefix.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/URIStringToImpPrefix.java index 35a958b55b..92c844b18b 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/URIStringToImpPrefix.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/URIStringToImpPrefix.java @@ -10,9 +10,9 @@ package org.opendaylight.yangtools.yang.parser.stmt.rfc6020; import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; /** - * Implementation-internal cache for looking up URI -> import prefix. URIs are taken in as Strings to save ourselves + * Implementation-internal cache for looking up URI to import prefix. URIs are taken in as Strings to save ourselves * some quality parsing time. */ -interface URIStringToImpPrefix extends IdentifierNamespace { +public interface URIStringToImpPrefix extends IdentifierNamespace { } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java index cfb9cd0ea7..e87aa4fa0c 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java @@ -12,7 +12,9 @@ import static org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour import static org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.treeScoped; import com.google.common.collect.ImmutableMap; +import java.util.Collection; import java.util.Map; +import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; import org.opendaylight.yangtools.yang.parser.spi.ExtensionNamespace; import org.opendaylight.yangtools.yang.parser.spi.GroupingNamespace; import org.opendaylight.yangtools.yang.parser.spi.IdentityNamespace; @@ -107,7 +109,7 @@ public final class YangInferencePipeline { .addSupport(sourceLocal(ImpPrefixToSemVerModuleIdentifier.class)) .build(); - private static final StatementSupportBundle STMT_DEF_BUNDLE = StatementSupportBundle + public static final StatementSupportBundle STMT_DEF_BUNDLE = StatementSupportBundle .derivedFrom(LINKAGE_BUNDLE) .addSupport(new YinElementStatementImpl.Definition()) .addSupport(new ArgumentStatementImpl.Definition()) @@ -143,7 +145,7 @@ public final class YangInferencePipeline { .addSupport(global(DerivedIdentitiesNamespace.class)) .build(); - private static final StatementSupportBundle FULL_DECL_BUNDLE = StatementSupportBundle + public static final StatementSupportBundle FULL_DECL_BUNDLE = StatementSupportBundle .derivedFrom(STMT_DEF_BUNDLE) .addSupport(new LeafStatementImpl.Definition()) .addSupport(new ConfigStatementImpl.Definition()) @@ -179,6 +181,7 @@ public final class YangInferencePipeline { public static final Map RFC6020_BUNDLES = ImmutableMap . builder() + .put(ModelProcessingPhase.INIT, INIT_BUNDLE) .put(ModelProcessingPhase.SOURCE_PRE_LINKAGE, PRE_LINKAGE_BUNDLE) .put(ModelProcessingPhase.SOURCE_LINKAGE, LINKAGE_BUNDLE) .put(ModelProcessingPhase.STATEMENT_DEFINITION, STMT_DEF_BUNDLE) @@ -186,6 +189,14 @@ public final class YangInferencePipeline { .put(ModelProcessingPhase.EFFECTIVE_MODEL, FULL_DECL_BUNDLE) .build(); + public static final Map> RFC6020_VALIDATION_BUNDLE = ImmutableMap + .> builder() + .put(ValidationBundleType.SUPPORTED_REFINE_SUBSTATEMENTS, YangValidationBundles.SUPPORTED_REFINE_SUBSTATEMENTS) + .put(ValidationBundleType.SUPPORTED_AUGMENT_TARGETS, YangValidationBundles.SUPPORTED_AUGMENT_TARGETS) + .put(ValidationBundleType.SUPPORTED_CASE_SHORTHANDS, YangValidationBundles.SUPPORTED_CASE_SHORTHANDS) + .put(ValidationBundleType.SUPPORTED_DATA_NODES, YangValidationBundles.SUPPORTED_DATA_NODES) + .build(); + public static final CrossSourceStatementReactor RFC6020_REACTOR = CrossSourceStatementReactor .builder() .setBundle(ModelProcessingPhase.INIT, INIT_BUNDLE) diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/CustomInferencePipeline.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/CustomInferencePipeline.java new file mode 100644 index 0000000000..6f41833bbc --- /dev/null +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/CustomInferencePipeline.java @@ -0,0 +1,27 @@ +/* + * 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.thirdparty.plugin; + +import static org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.sourceLocal; + +import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.CustomStatementParserBuilder; + +public final class CustomInferencePipeline { + public static final CrossSourceStatementReactor CUSTOM_REACTOR = new CustomStatementParserBuilder() + .addDefaultRFC6020Bundles() + .addStatementSupport(ModelProcessingPhase.FULL_DECLARATION, + new ThirdPartyExtensionStatementImpl.ThirdPartyExtensionSupport()) + .addNamespaceSupport(ModelProcessingPhase.FULL_DECLARATION, sourceLocal(ThirdPartyNamespace.class)) + .build(); + + private CustomInferencePipeline() { + throw new UnsupportedOperationException("Utility class"); + } +} diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionEffectiveStatementImpl.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionEffectiveStatementImpl.java new file mode 100644 index 0000000000..0a7dcfa2dd --- /dev/null +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionEffectiveStatementImpl.java @@ -0,0 +1,73 @@ +/* + * 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.thirdparty.plugin; + +import com.google.common.annotations.Beta; +import java.util.Objects; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.stmt.UnknownStatement; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.UnknownEffectiveStatementBase; + +@Beta +public final class ThirdPartyExtensionEffectiveStatementImpl extends UnknownEffectiveStatementBase { + + private final SchemaPath path; + private final String valueFromNamespace; + + public ThirdPartyExtensionEffectiveStatementImpl(final StmtContext, ?> ctx) { + super(ctx); + path = ctx.getParentContext().getSchemaPath().get().createChild(getNodeType()); + valueFromNamespace = ctx.getFromNamespace(ThirdPartyNamespace.class, ctx); + } + + public String getValueFromNamespace() { + return valueFromNamespace; + } + + @Override + public QName getQName() { + return getNodeType(); + } + + @Override + public SchemaPath getPath() { + return path; + } + + @Override + public int hashCode() { + return Objects.hash(path, getNodeType(), getNodeParameter()); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ThirdPartyExtensionEffectiveStatementImpl other = (ThirdPartyExtensionEffectiveStatementImpl) obj; + if (!Objects.equals(path, other.path)) { + return false; + } + if (!Objects.equals(getNodeType(), other.getNodeType())) { + return false; + } + if (!Objects.equals(getNodeParameter(), other.getNodeParameter())) { + return false; + } + return true; + } +} diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionPluginTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionPluginTest.java new file mode 100644 index 0000000000..4aca084c27 --- /dev/null +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionPluginTest.java @@ -0,0 +1,54 @@ +/* + * 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.thirdparty.plugin; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.net.URISyntaxException; +import java.util.List; +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.UnknownSchemaNode; +import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.EffectiveSchemaContext; + +public class ThirdPartyExtensionPluginTest { + private static final String NS = "urn:opendaylight:yang:extension:third-party"; + private static final String REV = "2016-06-09"; + + @Test + public void test() throws FileNotFoundException, URISyntaxException, ReactorException { + final CrossSourceStatementReactor.BuildAction reactor = CustomInferencePipeline.CUSTOM_REACTOR.newBuild(); + final FileInputStream yangFile = new FileInputStream(new File(getClass().getResource("/plugin-test/foo.yang") + .toURI())); + reactor.addSource(new YangStatementSourceImpl(yangFile)); + + final EffectiveSchemaContext schema = reactor.buildEffective(); + final DataSchemaNode dataChildByName = schema.getDataChildByName(QName.create(NS, REV, "root")); + assertTrue(dataChildByName instanceof ContainerSchemaNode); + final ContainerSchemaNode root = (ContainerSchemaNode) dataChildByName; + + final List unknownSchemaNodes = root.getUnknownSchemaNodes(); + assertEquals(1, unknownSchemaNodes.size()); + + final UnknownSchemaNode unknownSchemaNode = unknownSchemaNodes.get(0); + assertTrue(unknownSchemaNode instanceof ThirdPartyExtensionEffectiveStatementImpl); + + final ThirdPartyExtensionEffectiveStatementImpl thirdPartyExtensionStmt = (ThirdPartyExtensionEffectiveStatementImpl) unknownSchemaNode; + assertEquals("Third-party namespace test.", thirdPartyExtensionStmt.getValueFromNamespace()); + assertEquals("plugin test", thirdPartyExtensionStmt.argument()); + } +} diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionStatementImpl.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionStatementImpl.java new file mode 100644 index 0000000000..2636da86e7 --- /dev/null +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionStatementImpl.java @@ -0,0 +1,59 @@ +/* + * 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.thirdparty.plugin; + +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.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.spi.meta.StmtContext.Mutable; + +public class ThirdPartyExtensionStatementImpl extends AbstractDeclaredStatement implements + UnknownStatement { + + ThirdPartyExtensionStatementImpl(final StmtContext, ?> context) { + super(context); + } + + public static class ThirdPartyExtensionSupport + extends + AbstractStatementSupport, EffectiveStatement>> { + + public ThirdPartyExtensionSupport() { + super(ThirdPartyExtensionsMapping.THIRD_PARTY_EXTENSION); + } + + @Override + public String parseArgumentValue(final StmtContext ctx, final String value) { + return value; + } + + @Override + public void onFullDefinitionDeclared( + final Mutable, EffectiveStatement>> stmt) { + stmt.addToNs(ThirdPartyNamespace.class, stmt, "Third-party namespace test."); + } + + @Override + public UnknownStatement createDeclared(final StmtContext, ?> ctx) { + return new ThirdPartyExtensionStatementImpl(ctx); + } + + @Override + public EffectiveStatement> createEffective( + final StmtContext, EffectiveStatement>> ctx) { + return new ThirdPartyExtensionEffectiveStatementImpl(ctx); + } + } + + @Override + public String getArgument() { + return argument(); + } +} diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionsMapping.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionsMapping.java new file mode 100644 index 0000000000..3e5bbd1f80 --- /dev/null +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyExtensionsMapping.java @@ -0,0 +1,88 @@ +/* + * 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.thirdparty.plugin; + +import com.google.common.annotations.Beta; +import com.google.common.base.Preconditions; +import javax.annotation.Nonnull; +import javax.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; + +@Beta +public enum ThirdPartyExtensionsMapping implements StatementDefinition { + THIRD_PARTY_EXTENSION("urn:opendaylight:yang:extension:third-party", "2016-06-09", + ThirdPartyExtensionStatementImpl.class, ThirdPartyExtensionEffectiveStatementImpl.class, + "third-party-extension", "argument-name", false); + + private final Class> type; + private final Class> effectiveType; + private final QName name; + private final QName argument; + private final boolean yinElement; + + ThirdPartyExtensionsMapping(final String namespace, final String revision, + final Class> declared, + final Class> effective, final String nameStr, final String argumentStr, + final boolean yinElement) { + type = Preconditions.checkNotNull(declared); + effectiveType = Preconditions.checkNotNull(effective); + name = createQName(namespace, revision, nameStr); + argument = createQName(namespace, revision, argumentStr); + this.yinElement = yinElement; + } + + private ThirdPartyExtensionsMapping(final String namespace, final Class> declared, + final Class> effective, final String nameStr, final String argumentStr, + final boolean yinElement) { + type = Preconditions.checkNotNull(declared); + effectiveType = Preconditions.checkNotNull(effective); + name = createQName(namespace, nameStr); + argument = createQName(namespace, argumentStr); + this.yinElement = yinElement; + } + + @Nonnull + private static QName createQName(final String namespace, final String localName) { + return QName.create(namespace, localName).intern(); + } + + @Nonnull + private static QName createQName(final String namespace, final String revision, final String localName) { + return QName.create(namespace, revision, localName).intern(); + } + + @Override + public QName getStatementName() { + return name; + } + + @Override + @Nullable + public QName getArgumentName() { + return argument; + } + + @Override + @Nonnull + public Class> getDeclaredRepresentationClass() { + return type; + } + + @Override + public Class> getEffectiveRepresentationClass() { + return effectiveType; + } + + @Override + public boolean isArgumentYinElement() { + return yinElement; + } +} diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyNamespace.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyNamespace.java new file mode 100644 index 0000000000..4942ee4051 --- /dev/null +++ b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/thirdparty/plugin/ThirdPartyNamespace.java @@ -0,0 +1,20 @@ +/* + * 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.thirdparty.plugin; + +import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; + +/** + * + * ThirdPartyNamespace + * + */ +public interface ThirdPartyNamespace extends IdentifierNamespace, String> { + +} diff --git a/yang/yang-parser-impl/src/test/resources/plugin-test/foo.yang b/yang/yang-parser-impl/src/test/resources/plugin-test/foo.yang new file mode 100644 index 0000000000..f9fd922896 --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/plugin-test/foo.yang @@ -0,0 +1,15 @@ +module foo { + namespace "urn:opendaylight:yang:extension:third-party"; + prefix foo; + yang-version 1; + + revision 2016-06-09; + + container root { + foo:third-party-extension "plugin test"; + } + + extension third-party-extension { + argument argument-name; + } +} -- 2.36.6