Bug 6873: [Yang 1.1] Add support for "require-instance" in leafref 97/49697/7
authorIgor Foltin <ifoltin@cisco.com>
Wed, 21 Dec 2016 13:03:53 +0000 (14:03 +0100)
committerRobert Varga <nite@hq.sk>
Thu, 12 Jan 2017 10:19:32 +0000 (10:19 +0000)
Allow leafref type to have require-instance substatement in Yang 1.1 models.

Change-Id: I96cc337176abbb3e2fdb1ae22a83ba7810190fbe
Signed-off-by: Igor Foltin <ifoltin@cisco.com>
16 files changed:
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/BaseLeafrefType.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/DerivedLeafrefType.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/InstanceIdentifierTypeBuilder.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/LeafrefTypeBuilder.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/RequireInstanceRestrictedTypeBuilder.java [new file with mode: 0644]
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/RestrictedLeafrefType.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/RestrictedTypes.java
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/LeafrefTest.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/LeafrefSpecificationImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/LeafrefSpecificationEffectiveStatementImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/LeafrefTypeEffectiveStatementImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/LeafrefSpecificationRfc7950Support.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/LeafrefStatementTest.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/leafref-stmt/foo.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/rfc7950/leafref-stmt/foo10.yang [new file with mode: 0644]

index e4ea49ad96e15a44d50721fc081da73f5c0670ff..6ffe8c59d691df79b36cc2e6e30d5dded902ae0f 100644 (file)
@@ -16,10 +16,13 @@ import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 
 final class BaseLeafrefType extends AbstractBaseType<LeafrefTypeDefinition> implements LeafrefTypeDefinition {
     private final RevisionAwareXPath pathStatement;
+    private final boolean requireInstance;
 
-    BaseLeafrefType(final SchemaPath path, final RevisionAwareXPath pathStatement, final List<UnknownSchemaNode> unknownSchemaNodes) {
+    BaseLeafrefType(final SchemaPath path, final RevisionAwareXPath pathStatement, final boolean requireInstance,
+            final List<UnknownSchemaNode> unknownSchemaNodes) {
         super(path, unknownSchemaNodes);
         this.pathStatement = Preconditions.checkNotNull(pathStatement);
+        this.requireInstance = requireInstance;
     }
 
     @Override
@@ -27,6 +30,11 @@ final class BaseLeafrefType extends AbstractBaseType<LeafrefTypeDefinition> impl
         return pathStatement;
     }
 
+    @Override
+    public boolean requireInstance() {
+        return requireInstance;
+    }
+
     @Override
     public int hashCode() {
         return TypeDefinitions.hashCode(this);
index 7928270c600e83f61613371bb1779d1387a0272e..3cda6bea20be1ec3b52fb1fef6dd2c98ebe7f0b3 100644 (file)
@@ -15,6 +15,7 @@ import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 
 final class DerivedLeafrefType extends AbstractDerivedType<LeafrefTypeDefinition> implements LeafrefTypeDefinition {
+
     DerivedLeafrefType(final LeafrefTypeDefinition baseType, final SchemaPath path, final Object defaultValue,
         final String description, final String reference, final Status status, final String units,
         final Collection<UnknownSchemaNode> unknownSchemaNodes) {
@@ -26,6 +27,11 @@ final class DerivedLeafrefType extends AbstractDerivedType<LeafrefTypeDefinition
         return baseType().getPathStatement();
     }
 
+    @Override
+    public boolean requireInstance() {
+        return baseType().requireInstance();
+    }
+
     @Override
     public int hashCode() {
         return TypeDefinitions.hashCode(this);
index 8e159ee4766c96dfe373acb16e6135b344a2b14a..8143a24448cde5d71d85d353d9d107f9ebb0741e 100644 (file)
@@ -11,30 +11,18 @@ import com.google.common.base.Preconditions;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
 
-public final class InstanceIdentifierTypeBuilder extends AbstractRestrictedTypeBuilder<InstanceIdentifierTypeDefinition> {
-    private boolean requireInstance;
+public final class InstanceIdentifierTypeBuilder extends RequireInstanceRestrictedTypeBuilder<InstanceIdentifierTypeDefinition> {
 
     InstanceIdentifierTypeBuilder(final InstanceIdentifierTypeDefinition baseType, final SchemaPath path) {
         super(Preconditions.checkNotNull(baseType), path);
-        this.requireInstance = baseType.requireInstance();
-    }
-
-    public InstanceIdentifierTypeBuilder setRequireInstance(final boolean requireInstance) {
-        if (this.requireInstance) {
-            Preconditions.checkArgument(!requireInstance, "Cannot switch require-instance off in type %s", getPath());
-        }
-
-        this.requireInstance = requireInstance;
-        touch();
-        return this;
     }
 
     @Override
     InstanceIdentifierTypeDefinition buildType() {
-        if (requireInstance == getBaseType().requireInstance()) {
+        if (getRequireInstance() == getBaseType().requireInstance()) {
             return getBaseType();
         }
 
-        return new RestrictedInstanceIdentifierType(getBaseType(), getPath(), getUnknownSchemaNodes(), requireInstance);
+        return new RestrictedInstanceIdentifierType(getBaseType(), getPath(), getUnknownSchemaNodes(), getRequireInstance());
     }
 }
index f19b589f7683cec2414bc86dd6502a216db8d425..03dabd7b0d62a463d28330afa45efff40c0e1bba 100644 (file)
@@ -13,7 +13,7 @@ import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 
-public final class LeafrefTypeBuilder extends TypeBuilder<LeafrefTypeDefinition> {
+public final class LeafrefTypeBuilder extends RequireInstanceRestrictedTypeBuilder<LeafrefTypeDefinition> {
     private RevisionAwareXPath pathStatement;
 
     LeafrefTypeBuilder(final SchemaPath path) {
@@ -27,7 +27,7 @@ public final class LeafrefTypeBuilder extends TypeBuilder<LeafrefTypeDefinition>
     }
 
     @Override
-    public LeafrefTypeDefinition build() {
-        return new BaseLeafrefType(getPath(), pathStatement, getUnknownSchemaNodes());
+    LeafrefTypeDefinition buildType() {
+        return new BaseLeafrefType(getPath(), pathStatement, getRequireInstance(), getUnknownSchemaNodes());
     }
 }
diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/RequireInstanceRestrictedTypeBuilder.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/RequireInstanceRestrictedTypeBuilder.java
new file mode 100644 (file)
index 0000000..6d4b988
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.model.util.type;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+
+@Beta
+public abstract class RequireInstanceRestrictedTypeBuilder<T extends TypeDefinition<T>>
+        extends AbstractRestrictedTypeBuilder<T> {
+
+    private boolean requireInstance;
+
+    RequireInstanceRestrictedTypeBuilder(final T baseType, final SchemaPath path) {
+        super(baseType, path);
+    }
+
+    public final void setRequireInstance(final boolean requireInstance) {
+        if (this.requireInstance) {
+            Preconditions.checkArgument(requireInstance, "Cannot switch off require-instance in type %s", getPath());
+        }
+
+        this.requireInstance = requireInstance;
+        touch();
+    }
+
+    final boolean getRequireInstance() {
+        return requireInstance;
+    }
+}
index e3e159432068c26a1a4590e09c68d9070fd9f070..b589b20297de92173e7435543a823f8c1d4efa43 100644 (file)
@@ -14,9 +14,14 @@ import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 
 final class RestrictedLeafrefType extends AbstractRestrictedType<LeafrefTypeDefinition> implements LeafrefTypeDefinition {
+
+    private final boolean requireInstance;
+
     RestrictedLeafrefType(final LeafrefTypeDefinition baseType, final SchemaPath path,
-            final Collection<UnknownSchemaNode> unknownSchemaNodes) {
+            final Collection<UnknownSchemaNode> unknownSchemaNodes, final boolean requireInstance) {
         super(baseType, path, unknownSchemaNodes);
+
+        this.requireInstance = requireInstance;
     }
 
     @Override
@@ -24,6 +29,11 @@ final class RestrictedLeafrefType extends AbstractRestrictedType<LeafrefTypeDefi
         return getBaseType().getPathStatement();
     }
 
+    @Override
+    public boolean requireInstance() {
+        return requireInstance;
+    }
+
     @Override
     public int hashCode() {
         return TypeDefinitions.hashCode(this);
index 2a04f7950347accc19806d392b9dd77e8984b5ad..fe31615fcbf5fb04d42695701391fefe831c7ef7 100644 (file)
@@ -144,11 +144,15 @@ public final class RestrictedTypes {
         return new InstanceIdentifierTypeBuilder(baseType, path);
     }
 
-    public static TypeBuilder<LeafrefTypeDefinition> newLeafrefBuilder(final LeafrefTypeDefinition baseType, final SchemaPath path) {
-        return new AbstractRestrictedTypeBuilder<LeafrefTypeDefinition>(baseType, path) {
+    public static RequireInstanceRestrictedTypeBuilder<LeafrefTypeDefinition> newLeafrefBuilder(
+            final LeafrefTypeDefinition baseType, final SchemaPath path) {
+        return new RequireInstanceRestrictedTypeBuilder<LeafrefTypeDefinition>(baseType, path) {
             @Override
             LeafrefTypeDefinition buildType() {
-                return new RestrictedLeafrefType(getBaseType(), getPath(), getUnknownSchemaNodes());
+                if (getRequireInstance() == getBaseType().requireInstance()) {
+                    return getBaseType();
+                }
+                return new RestrictedLeafrefType(getBaseType(), getPath(), getUnknownSchemaNodes(), getRequireInstance());
             }
         };
     }
index 1972d94c25ef6d601b7ca8afc495563d0ff6e814..2cd69698524137252bccedfe5af7c38e68abf6b4 100644 (file)
@@ -13,12 +13,15 @@ import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.opendaylight.yangtools.yang.model.util.type.BaseTypes;
+import org.opendaylight.yangtools.yang.model.util.type.LeafrefTypeBuilder;
 
 public class LeafrefTest {
 
@@ -52,4 +55,33 @@ public class LeafrefTest {
         assertFalse("Objects shouldn't be equal.", leafref.equals(null));
         assertFalse("Objects shouldn't be equal.", leafref.equals("test"));
     }
+
+    @Test
+    public void testRequireInstanceSubstatement() {
+        final SchemaPath schemaPath = SchemaPath.create(true, QName.create("my-cont"), QName.create("my-leafref"));
+        final RevisionAwareXPathImpl path = new RevisionAwareXPathImpl("../my-leaf", false);
+
+        LeafrefTypeBuilder leafrefTypeBuilder = BaseTypes.leafrefTypeBuilder(schemaPath).setPathStatement(path);
+
+        leafrefTypeBuilder.setRequireInstance(false);
+        LeafrefTypeDefinition leafref = leafrefTypeBuilder.build();
+        assertFalse(leafref.requireInstance());
+
+        leafrefTypeBuilder.setRequireInstance(true);
+        leafref = leafrefTypeBuilder.build();
+        assertTrue(leafref.requireInstance());
+
+        leafrefTypeBuilder.setRequireInstance(true);
+        leafref = leafrefTypeBuilder.build();
+        assertTrue(leafref.requireInstance());
+
+        try {
+            leafrefTypeBuilder.setRequireInstance(false);
+            fail("An IllegalArgumentException should have been thrown.");
+        } catch (IllegalArgumentException ex) {
+            assertEquals("Cannot switch off require-instance in type AbsoluteSchemaPath{path=[my-cont, my-leafref]}",
+                    ex.getMessage());
+        }
+
+    }
 }
index 715de850080d1c6468b956c81a3bad305e7858fd..dadc28d952e0a8920f7e3bc64cf5ddc4cbb8ec7e 100644 (file)
@@ -11,8 +11,9 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Verify;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableTable;
 import com.google.common.collect.Multimap;
+import com.google.common.collect.Table;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -66,6 +67,7 @@ import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.TypeUtils;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.UnionSpecificationImpl;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.UnknownStatementImpl;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.LeafrefSpecificationRfc7950Support;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -108,16 +110,18 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh
     }
 
     private static final Logger LOG = LoggerFactory.getLogger(SourceSpecificContext.class);
-    private static final Map<String, StatementSupport<?, ?, ?>> BUILTIN_TYPE_SUPPORTS =
-            ImmutableMap.<String, StatementSupport<?, ?, ?>>builder()
-            .put(TypeUtils.DECIMAL64, new Decimal64SpecificationImpl.Definition())
-            .put(TypeUtils.UNION, new UnionSpecificationImpl.Definition())
-            .put(TypeUtils.ENUMERATION, new EnumSpecificationImpl.Definition())
-            .put(TypeUtils.LEAF_REF, new LeafrefSpecificationImpl.Definition())
-            .put(TypeUtils.BITS, new BitsSpecificationImpl.Definition())
-            .put(TypeUtils.IDENTITY_REF, new IdentityRefSpecificationImpl.Definition())
-            .put(TypeUtils.INSTANCE_IDENTIFIER, new InstanceIdentifierSpecificationImpl.Definition())
-            .build();
+    private static final Table<YangVersion, String, StatementSupport<?, ?, ?>> BUILTIN_TYPE_SUPPORTS =
+            ImmutableTable.<YangVersion, String, StatementSupport<?, ?, ?>>builder()
+            .put(YangVersion.VERSION_1, TypeUtils.DECIMAL64, new Decimal64SpecificationImpl.Definition())
+            .put(YangVersion.VERSION_1, TypeUtils.UNION, new UnionSpecificationImpl.Definition())
+            .put(YangVersion.VERSION_1, TypeUtils.ENUMERATION, new EnumSpecificationImpl.Definition())
+            .put(YangVersion.VERSION_1, TypeUtils.LEAF_REF, new LeafrefSpecificationImpl.Definition())
+            .put(YangVersion.VERSION_1_1, TypeUtils.LEAF_REF, new LeafrefSpecificationRfc7950Support())
+            .put(YangVersion.VERSION_1, TypeUtils.BITS, new BitsSpecificationImpl.Definition())
+            .put(YangVersion.VERSION_1, TypeUtils.IDENTITY_REF, new IdentityRefSpecificationImpl.Definition())
+            .put(YangVersion.VERSION_1, TypeUtils.INSTANCE_IDENTIFIER, new InstanceIdentifierSpecificationImpl.Definition())
+                    .build();
+
     private static final QName TYPE = YangStmtMapping.TYPE.getStatementName();
 
     private final Multimap<ModelProcessingPhase, ModifierImpl> modifiers = HashMultimap.create();
@@ -169,7 +173,7 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh
                 def = new StatementDefinitionContext<>(extension);
             } else {
                 // type-body-stmts
-                def = resolveTypeBodyStmts(name.getLocalName());
+                def = resolveTypeBodyStmts(name.getLocalName(), getRootVersion());
             }
         } else if (current != null && current.definition().getRepresentingClass().equals(UnknownStatementImpl.class)) {
             /*
@@ -392,8 +396,14 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh
         }
     }
 
-    private static StatementDefinitionContext<?, ?, ?> resolveTypeBodyStmts(final String typeArgument) {
-        final StatementSupport<?, ?, ?> support = BUILTIN_TYPE_SUPPORTS.get(typeArgument);
+    private static StatementDefinitionContext<?, ?, ?> resolveTypeBodyStmts(final String typeArgument,
+            final YangVersion version) {
+        StatementSupport<?, ?, ?> support = BUILTIN_TYPE_SUPPORTS.get(version, typeArgument);
+
+        if (support == null) {
+            support = BUILTIN_TYPE_SUPPORTS.get(YangVersion.VERSION_1, typeArgument);
+        }
+
         return support == null ? null : new StatementDefinitionContext<>(support);
     }
 
index e9e802d3a06fdeb393d8a7cfc34d47bdc44dab55..2526258c3993bc31c8dc1b0873c36aa43e005c4f 100644 (file)
@@ -8,9 +8,11 @@
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.PathStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.RequireInstanceStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement.LeafrefSpecification;
 import org.opendaylight.yangtools.yang.parser.spi.SubstatementValidator;
 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement;
@@ -23,7 +25,6 @@ public class LeafrefSpecificationImpl extends AbstractDeclaredStatement<String>
     private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(YangStmtMapping
             .TYPE)
             .addMandatory(YangStmtMapping.PATH)
-            .addOptional(YangStmtMapping.REQUIRE_INSTANCE)
             .build();
 
     protected LeafrefSpecificationImpl(
@@ -73,4 +74,10 @@ public class LeafrefSpecificationImpl extends AbstractDeclaredStatement<String>
         return firstDeclared(PathStatement.class);
     }
 
+    @Nullable
+    @Override
+    public RequireInstanceStatement getRequireInstance() {
+        return firstDeclared(RequireInstanceStatement.class);
+    }
+
 }
index c95023597533d67da512ea9dd800a0e71ea1de3c..abeae8a6b490a4b61b35586192947dda35b84dcd 100644 (file)
@@ -17,6 +17,7 @@ import org.opendaylight.yangtools.yang.model.util.type.LeafrefTypeBuilder;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.DeclaredEffectiveStatementBase;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.PathEffectiveStatementImpl;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.RequireInstanceEffectiveStatementImpl;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.UnknownEffectiveStatementImpl;
 
 public final class LeafrefSpecificationEffectiveStatementImpl extends DeclaredEffectiveStatementBase<String, LeafrefSpecification>
@@ -32,8 +33,9 @@ public final class LeafrefSpecificationEffectiveStatementImpl extends DeclaredEf
         for (final EffectiveStatement<?, ?> stmt : effectiveSubstatements()) {
             if (stmt instanceof PathEffectiveStatementImpl) {
                 builder.setPathStatement(((PathEffectiveStatementImpl) stmt).argument());
-            }
-            if (stmt instanceof UnknownEffectiveStatementImpl) {
+            } else if(stmt instanceof RequireInstanceEffectiveStatementImpl) {
+                builder.setRequireInstance(((RequireInstanceEffectiveStatementImpl)stmt).argument());
+            } else if (stmt instanceof UnknownEffectiveStatementImpl) {
                 builder.addUnknownSchemaNode((UnknownEffectiveStatementImpl)stmt);
             }
         }
index 5ac9768328cb52a1742fa153aeff459a73fcf96a..2d9f4eb04ccef184ec56d4d99f01742ef772c955 100644 (file)
@@ -8,17 +8,46 @@
 
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type;
 
+import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.TypeStatement;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.type.RequireInstanceRestrictedTypeBuilder;
 import org.opendaylight.yangtools.yang.model.util.type.RestrictedTypes;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.TypeUtils;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.DeclaredEffectiveStatementBase;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.RequireInstanceEffectiveStatementImpl;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.UnknownEffectiveStatementImpl;
+
+public final class LeafrefTypeEffectiveStatementImpl extends DeclaredEffectiveStatementBase<String, TypeStatement>
+        implements TypeEffectiveStatement<TypeStatement> {
+
+    private final LeafrefTypeDefinition typeDefinition;
 
-public final class LeafrefTypeEffectiveStatementImpl extends AbstractTypeEffectiveStatement<LeafrefTypeDefinition> {
     public LeafrefTypeEffectiveStatementImpl(
             final StmtContext<String, TypeStatement, EffectiveStatement<String, TypeStatement>> ctx,
             final LeafrefTypeDefinition baseType) {
-        super(ctx, RestrictedTypes.newLeafrefBuilder(baseType, TypeUtils.typeEffectiveSchemaPath(ctx)));
+        super(ctx);
+
+        final RequireInstanceRestrictedTypeBuilder<LeafrefTypeDefinition> builder =
+                RestrictedTypes.newLeafrefBuilder(baseType, TypeUtils.typeEffectiveSchemaPath(ctx));
+
+        for (final EffectiveStatement<?, ?> stmt : effectiveSubstatements()) {
+            if (stmt instanceof RequireInstanceEffectiveStatementImpl) {
+                builder.setRequireInstance(((RequireInstanceEffectiveStatementImpl) stmt).argument());
+            } else if (stmt instanceof UnknownEffectiveStatementImpl) {
+                builder.addUnknownSchemaNode((UnknownEffectiveStatementImpl)stmt);
+            }
+        }
+
+        typeDefinition = builder.build();
+    }
+
+    @Nonnull
+    @Override
+    public LeafrefTypeDefinition getTypeDefinition() {
+        return typeDefinition;
     }
 }
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/LeafrefSpecificationRfc7950Support.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/LeafrefSpecificationRfc7950Support.java
new file mode 100644 (file)
index 0000000..3f5b1b9
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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.parser.stmt.rfc7950;
+
+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.stmt.rfc6020.LeafrefSpecificationImpl;
+
+/**
+ * Class providing necessary support for processing YANG 1.1 leafref statement.
+ */
+@Beta
+public class LeafrefSpecificationRfc7950Support extends LeafrefSpecificationImpl.Definition {
+    private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(YangStmtMapping
+            .TYPE)
+            .addMandatory(YangStmtMapping.PATH)
+            .addOptional(YangStmtMapping.REQUIRE_INSTANCE)
+            .build();
+
+    @Override
+    protected SubstatementValidator getSubstatementValidator() {
+        return SUBSTATEMENT_VALIDATOR;
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/LeafrefStatementTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/stmt/rfc7950/LeafrefStatementTest.java
new file mode 100644 (file)
index 0000000..82dc511
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.parser.stmt.rfc7950;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.Set;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.stmt.StmtTestUtils;
+
+public class LeafrefStatementTest {
+
+    @Test
+    public void testRequireInstanceInLeafrefs() throws ReactorException, FileNotFoundException, URISyntaxException,
+            ParseException {
+        final SchemaContext schemaContext = StmtTestUtils.parseYangSource("/rfc7950/leafref-stmt/foo.yang");
+        assertNotNull(schemaContext);
+
+        final Date revision = SimpleDateFormatUtil.getRevisionFormat().parse("2016-12-20");
+
+        final Module foo = schemaContext.findModuleByName("foo", revision);
+        assertNotNull(foo);
+
+        final Set<TypeDefinition<?>> typeDefinitions = foo.getTypeDefinitions();
+        assertEquals(1, typeDefinitions.size());
+
+        final TypeDefinition<?> typeDefinition = typeDefinitions.iterator().next();
+        final LeafrefTypeDefinition leafrefTypeDefinition = (LeafrefTypeDefinition) typeDefinition;
+        assertTrue(leafrefTypeDefinition.requireInstance());
+
+        final LeafSchemaNode leafrefA = (LeafSchemaNode) foo.getDataChildByName(QName.create(foo.getQNameModule(),
+                "leafref-a"));
+        assertNotNull(leafrefA);
+        assertRequireInstanceInLeafref(leafrefA, true);
+
+        final LeafSchemaNode leafrefB = (LeafSchemaNode) foo.getDataChildByName(QName.create(foo.getQNameModule(),
+                "leafref-b"));
+        assertNotNull(leafrefB);
+        assertRequireInstanceInLeafref(leafrefB, true);
+
+        final LeafSchemaNode leafrefC = (LeafSchemaNode) foo.getDataChildByName(QName.create(foo.getQNameModule(),
+                "leafref-c"));
+        assertNotNull(leafrefC);
+        assertRequireInstanceInLeafref(leafrefC, false);
+    }
+
+    private static void assertRequireInstanceInLeafref(final LeafSchemaNode leaf, final boolean requireInstance) {
+        final LeafrefTypeDefinition leafrefTypeDefnition = (LeafrefTypeDefinition) leaf.getType();
+        assertEquals(requireInstance, leafrefTypeDefnition.requireInstance());
+    }
+
+    @Test
+    public void testInvalidYang10() throws ReactorException, FileNotFoundException, URISyntaxException, ParseException {
+        try {
+            StmtTestUtils.parseYangSource("/rfc7950/leafref-stmt/foo10.yang");
+            fail("Test should fail due to invalid Yang 1.0");
+        } catch (final ReactorException e) {
+            assertTrue(e.getCause().getMessage().startsWith("REQUIRE_INSTANCE is not valid for TYPE"));
+        }
+    }
+}
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/leafref-stmt/foo.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/leafref-stmt/foo.yang
new file mode 100644 (file)
index 0000000..ba39f23
--- /dev/null
@@ -0,0 +1,43 @@
+module foo {
+    namespace foo-ns;
+    prefix foo-prfx;
+    yang-version 1.1;
+
+    revision 2016-12-20;
+
+    leaf leafref-a {
+        type leafref {
+            path "../leaf-a";
+            require-instance true;
+        }
+    }
+
+    leaf leaf-a {
+        type string;
+    }
+
+    leaf leafref-b {
+        type leafref-typedef;
+    }
+
+    leaf leaf-b {
+        type string;
+    }
+
+    typedef leafref-typedef {
+        type leafref {
+            path "../leaf-b";
+            require-instance true;
+        }
+    }
+
+    leaf leafref-c {
+        type leafref {
+            path "../leaf-c";
+        }
+    }
+
+    leaf leaf-c {
+        type string;
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/rfc7950/leafref-stmt/foo10.yang b/yang/yang-parser-impl/src/test/resources/rfc7950/leafref-stmt/foo10.yang
new file mode 100644 (file)
index 0000000..f6b574c
--- /dev/null
@@ -0,0 +1,18 @@
+module foo10 {
+    namespace foo10-ns;
+    prefix foo10-prfx;
+    yang-version 1;
+
+    revision 2016-12-20;
+
+    leaf leafref-a {
+        type leafref {
+            path "../leaf-a";
+            require-instance false;
+        }
+    }
+
+    leaf leaf-a {
+        type string;
+    }
+}
\ No newline at end of file