import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNodeForRelativeXPath;
import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
+
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import com.google.common.io.BaseEncoding;
import org.opendaylight.yangtools.sal.binding.model.api.type.builder.MethodSignatureBuilder;
import org.opendaylight.yangtools.yang.binding.BindingMapping;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.util.Int32;
import org.opendaylight.yangtools.yang.model.util.Int64;
import org.opendaylight.yangtools.yang.model.util.Int8;
+import org.opendaylight.yangtools.yang.model.util.RevisionAwareXPathImpl;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
import org.opendaylight.yangtools.yang.model.util.StringType;
import org.opendaylight.yangtools.yang.model.util.Uint16;
import org.opendaylight.yangtools.yang.model.util.Uint32;
import org.opendaylight.yangtools.yang.model.util.Uint64;
import org.opendaylight.yangtools.yang.model.util.Uint8;
import org.opendaylight.yangtools.yang.model.util.UnionType;
+import org.opendaylight.yangtools.yang.parser.util.YangValidationException;
public final class TypeProviderImpl implements TypeProvider {
private static final Pattern NUMBERS_PATTERN = Pattern.compile("[0-9]+\\z");
return gtob.toInstance();
}
+ private boolean isLeafRefSelfReference(final LeafrefTypeDefinition leafref, final SchemaNode parentNode) {
+ final SchemaNode leafRefValueNode;
+ final RevisionAwareXPath leafRefXPath = leafref.getPathStatement();
+ final RevisionAwareXPath leafRefStrippedXPath = new RevisionAwareXPathImpl(leafRefXPath.toString()
+ .replaceAll("\\[(.*?)\\]", ""), leafRefXPath.isAbsolute());
+
+ ///// skip leafrefs in augments - they're checked once augments are resolved
+ final Iterator<QName> iterator = parentNode.getPath().getPathFromRoot().iterator();
+ boolean isAugmenting = false;
+ DataNodeContainer current = null;
+ DataSchemaNode dataChildByName;
+
+ while (iterator.hasNext() && !isAugmenting) {
+ final QName next = iterator.next();
+ if (current == null) {
+ dataChildByName = schemaContext.getDataChildByName(next);
+ } else {
+ dataChildByName = current.getDataChildByName(next);
+ }
+ if (dataChildByName != null) {
+ isAugmenting = dataChildByName.isAugmenting();
+ } else {
+ return false;
+ }
+ if (dataChildByName instanceof DataNodeContainer) {
+ current = (DataNodeContainer) dataChildByName;
+ }
+ }
+ if (isAugmenting) {
+ return false;
+ }
+ /////
+
+ Module parentModule = getParentModule(parentNode);
+ if (!leafRefStrippedXPath.isAbsolute()) {
+ leafRefValueNode = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemaContext, parentModule,
+ parentNode, leafRefStrippedXPath);
+ } else {
+ leafRefValueNode = SchemaContextUtil.findDataSchemaNode(schemaContext, parentModule, leafRefStrippedXPath);
+ }
+ return (leafRefValueNode != null) ? leafRefValueNode.equals(parentNode) : false;
+ }
+
/**
* Returns JAVA <code>Type</code> for instances of the type
* <code>LeafrefTypeDefinition</code> or
private Type javaTypeForLeafrefOrIdentityRef(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode) {
if (typeDefinition instanceof LeafrefTypeDefinition) {
final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
+ if (isLeafRefSelfReference(leafref, parentNode)) {
+ throw new YangValidationException("Leafref " + leafref.toString() + " is referencing itself, incoming" +
+ " StackOverFlowError detected.");
+ }
return provideTypeForLeafref(leafref, parentNode);
} else if (typeDefinition instanceof IdentityrefTypeDefinition) {
final IdentityrefTypeDefinition idref = (IdentityrefTypeDefinition) typeDefinition;
import com.google.common.base.Optional;
import java.io.File;
+import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
import org.opendaylight.yangtools.yang.model.util.BinaryType;
import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.opendaylight.yangtools.yang.parser.util.YangValidationException;
public class TypeProviderImplTest {
@Rule
public ExpectedException expException = ExpectedException.none();
+ @Test (expected = YangValidationException.class)
+ public void testLeafRefRelativeSelfReference() throws Exception {
+ File relative = new File(getClass().getResource("/leafref/leafref-relative-invalid.yang").toURI());
+
+ final YangParserImpl yangParser = new YangParserImpl();
+ final SchemaContext schemaContext = yangParser.parseFiles(Arrays.asList(relative));
+ final Module moduleRelative = schemaContext.findModuleByNamespace(new URI("urn:xml:ns:yang:lrr")).iterator().next();
+ final TypeProviderImpl typeProvider = new TypeProviderImpl(schemaContext);
+
+ DataSchemaNode leafref = ((ListSchemaNode) moduleRelative.getDataChildByName("neighbor")).getDataChildByName("neighbor-id");
+ LeafSchemaNode leaf = (LeafSchemaNode) leafref;
+ TypeDefinition<?> leafType = leaf.getType();
+ Type leafrefResolvedType = typeProvider.javaTypeForSchemaDefinitionType(leafType, leaf);
+ }
+
+ @Test (expected = YangValidationException.class)
+ public void testLeafRefAbsoluteSelfReference() throws Exception {
+ File relative = new File(getClass().getResource("/leafref/leafref-absolute-invalid.yang").toURI());
+
+ final YangParserImpl yangParser = new YangParserImpl();
+ final SchemaContext schemaContext = yangParser.parseFiles(Arrays.asList(relative));
+ final Module moduleRelative = schemaContext.findModuleByNamespace(new URI("urn:xml:ns:yang:lra")).iterator().next();
+ final TypeProviderImpl typeProvider = new TypeProviderImpl(schemaContext);
+
+ DataSchemaNode leafref = ((ListSchemaNode) moduleRelative.getDataChildByName("neighbor")).getDataChildByName("neighbor-id");
+ LeafSchemaNode leaf = (LeafSchemaNode) leafref;
+ TypeDefinition<?> leafType = leaf.getType();
+ Type leafrefResolvedType = typeProvider.javaTypeForSchemaDefinitionType(leafType, leaf);
+ }
+
+ @Test
+ public void testLeafRefRelativeAndAbsoluteValidReference() throws URISyntaxException {
+ File valid = new File(getClass().getResource("/leafref/leafref-valid.yang").toURI());
+
+ final YangParserImpl yangParser = new YangParserImpl();
+ final SchemaContext schemaContext = yangParser.parseFiles(Arrays.asList(valid));
+ final Module moduleValid = schemaContext.findModuleByNamespace(new URI("urn:xml:ns:yang:lrv")).iterator().next();
+ final TypeProviderImpl typeProvider = new TypeProviderImpl(schemaContext);
+
+ DataSchemaNode leafrefRel = ((ListSchemaNode) moduleValid.getDataChildByName("neighbor")).getDataChildByName
+ ("neighbor-id");
+ LeafSchemaNode leafRel = (LeafSchemaNode) leafrefRel;
+ TypeDefinition<?> leafTypeRel = leafRel.getType();
+ Type leafrefRelResolvedType = typeProvider.javaTypeForSchemaDefinitionType(leafTypeRel, leafRel);
+ assertNotNull(leafrefRelResolvedType);
+
+ DataSchemaNode leafrefAbs = ((ListSchemaNode) moduleValid.getDataChildByName("neighbor")).getDataChildByName
+ ("neighbor2-id");
+ LeafSchemaNode leafAbs = (LeafSchemaNode) leafrefAbs;
+ TypeDefinition<?> leafTypeAbs = leafAbs.getType();
+ Type leafrefAbsResolvedType = typeProvider.javaTypeForSchemaDefinitionType(leafTypeAbs, leafAbs);
+ assertNotNull(leafrefAbsResolvedType);
+ }
+
@Test
public void testMethodsOfTypeProviderImpl() throws URISyntaxException {
final YangParserImpl yangParser = new YangParserImpl();
--- /dev/null
+module leafref-absolute-invalid {
+ namespace "urn:xml:ns:yang:lra";
+ prefix lra;
+ revision "2015-02-25";
+
+ list neighbor {
+ description
+ "List of neighbors.";
+ leaf neighbor-id {
+ type leafref {
+ path "/lra:neighbor/lra:neighbor-id";
+ }
+ description "Neighbor.";
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+module leafref-relative-invalid {
+ namespace "urn:xml:ns:yang:lrr";
+ prefix lrr;
+ revision "2015-02-25";
+
+ list neighbor {
+ description
+ "List of neighbors.";
+ leaf neighbor-id {
+ type leafref {
+ path "../../neighbor/neighbor-id";
+ }
+ description "Neighbor.";
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+module leafref-valid {
+ namespace "urn:xml:ns:yang:lrv";
+ prefix lrv;
+ revision "2015-02-25";
+
+ list neighbor {
+ description
+ "List of neighbors.";
+ leaf neighbor-id {
+ type leafref {
+ path "../../neighbor/mystring";
+ }
+ description "Neighbor.";
+ }
+
+ leaf neighbor2-id {
+ type leafref {
+ path "/lrv:neighbor/lrv:mystring";
+ }
+ }
+
+ leaf mystring {
+ type string;
+ }
+ }
+}
\ No newline at end of file