From 6939c625f6a616a0109a014e00392c649f264b69 Mon Sep 17 00:00:00 2001 From: lsedlak Date: Thu, 25 Jul 2013 16:13:09 +0200 Subject: [PATCH] Fixed bug in resolving of conditional Revision Aware XPath. Fixed implementation in TypeProviderImpl - if leafref references the leaf through the conditional XPath the method will no more returns null but wrapped Type as java.lang.Object. Added test into GeneratedTypesTest for conditional XPath. Fixed controller-network-ne.yang - changed name of flow-tables to flow-tables2 - the build should no more fail. Fixed wrong transformation of yang namespace to java package in case that yang namespace contains numbers right after the "." Added check into BindingGeneratorUtil - validateJavaPackage. Refactored and commented SchemaContextUtil.java Signed-off-by: Lukas Sedlak --- .../binding/yang/types/TypeProviderImpl.java | 2 +- .../generator/impl/GeneratedTypesTest.java | 164 ++---- .../src/test/resources/demo-topology.yang | 2 +- .../abstract-topology@2013-02-08.yang | 6 + .../generator/util/BindingGeneratorUtil.java | 7 +- .../code-generator-demo/pom.xml | 53 -- .../opendaylight/controller/yang/Demo.java | 93 --- .../src/main/resources/demo-topology.yang | 223 -------- .../src/main/resources/demo/types1.yang | 80 --- .../src/main/resources/demo/types2.yang | 35 -- .../src/main/resources/demo/types3.yang | 35 -- .../src/main/yang/controller-network-ne.yang | 2 +- .../src/main/yang/demo-topology.yang} | 81 ++- .../yang/model/util/SchemaContextUtil.java | 533 +++++++++++++----- 14 files changed, 511 insertions(+), 805 deletions(-) delete mode 100644 opendaylight/sal/yang-prototype/code-generator/code-generator-demo/pom.xml delete mode 100644 opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/java/org/opendaylight/controller/yang/Demo.java delete mode 100644 opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo-topology.yang delete mode 100644 opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types1.yang delete mode 100644 opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types2.yang delete mode 100644 opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types3.yang rename opendaylight/sal/yang-prototype/code-generator/{code-generator-demo/src/main/resources/test-topology.yang => samples/maven-code-gen-sample/src/main/yang/demo-topology.yang} (66%) diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/main/java/org/opendaylight/controller/sal/binding/yang/types/TypeProviderImpl.java b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/main/java/org/opendaylight/controller/sal/binding/yang/types/TypeProviderImpl.java index b6d8de62e6..f650004ba2 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/main/java/org/opendaylight/controller/sal/binding/yang/types/TypeProviderImpl.java +++ b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/main/java/org/opendaylight/controller/sal/binding/yang/types/TypeProviderImpl.java @@ -221,7 +221,7 @@ public final class TypeProviderImpl implements TypeProvider { final String strXPath = xpath.toString(); if (strXPath != null) { - if (strXPath.matches(".*//[.* | .*//].*")) { + if (strXPath.contains("[")) { returnType = Types.typeForClass(Object.class); } else { final Module module = findParentModuleForTypeDefinition(schemaContext, leafrefType); diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/java/org/opendaylight/controller/sal/binding/generator/impl/GeneratedTypesTest.java b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/java/org/opendaylight/controller/sal/binding/generator/impl/GeneratedTypesTest.java index ce9f131b75..a8b3b487af 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/java/org/opendaylight/controller/sal/binding/generator/impl/GeneratedTypesTest.java +++ b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/java/org/opendaylight/controller/sal/binding/generator/impl/GeneratedTypesTest.java @@ -8,12 +8,14 @@ package org.opendaylight.controller.sal.binding.generator.impl; import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Set; +import org.junit.Ignore; import org.junit.Test; import org.opendaylight.controller.sal.binding.generator.api.BindingGenerator; import org.opendaylight.controller.sal.binding.model.api.GeneratedProperty; @@ -73,9 +75,8 @@ public class GeneratedTypesTest { assertNotNull(inetTypesPath); assertNotNull(yangTypesPath); - // final SchemaContext context = resolveSchemaContextFromFiles( - // topologyPath, interfacesPath, ifTypePath, inetTypesPath, - // yangTypesPath); + // final SchemaContext context = resolveSchemaContextFromFiles(topologyPath, interfacesPath, ifTypePath, + // inetTypesPath, yangTypesPath); final SchemaContext context = resolveSchemaContextFromFiles(topologyPath, interfacesPath, inetTypesPath, yangTypesPath); assertNotNull(context); @@ -94,6 +95,7 @@ public class GeneratedTypesTest { GeneratedType gtDest = null; GeneratedType gtTunnel = null; GeneratedTransferObject gtTunnelKey = null; + GeneratedType gtTopology = null; for (final Type type : genTypes) { String name = type.getName(); if ("InterfaceKey".equals(name)) { @@ -110,6 +112,8 @@ public class GeneratedTypesTest { gtTunnel = (GeneratedType) type; } else if ("TunnelKey".equals(name)) { gtTunnelKey = (GeneratedTransferObject) type; + } else if ("Topology".equals(name)) { + gtTopology = (GeneratedType) type; } } @@ -120,6 +124,21 @@ public class GeneratedTypesTest { assertNotNull(gtDest); assertNotNull(gtTunnel); assertNotNull(gtTunnelKey); + assertNotNull(gtTopology); + + // Topology + final List gtTopoMethods = gtTopology.getMethodDefinitions(); + assertNotNull(gtTopoMethods); + MethodSignature condLeafref = null; + for (final MethodSignature method : gtTopoMethods) { + if (method.getName().equals("getCondLeafref")) { + condLeafref = method; + } + } + assertNotNull(condLeafref); + Type condLeafRT = condLeafref.getReturnType(); + assertNotNull(condLeafRT); + assertEquals("java.lang.Object", condLeafRT.getFullyQualifiedName()); // InterfaceId final List gtIfcKeyProps = gtIfcKey.getProperties(); @@ -133,8 +152,7 @@ public class GeneratedTypesTest { assertNotNull(ifcIdProp); Type ifcIdPropType = ifcIdProp.getReturnType(); assertNotNull(ifcIdPropType); - assertFalse(ifcIdPropType.equals("java.lang.Void")); - assertEquals(ifcIdPropType.getName(), "String"); + assertEquals("java.lang.String", ifcIdPropType.getFullyQualifiedName()); // Interface final List gtIfcMethods = gtIfc.getMethodDefinitions(); @@ -151,14 +169,14 @@ public class GeneratedTypesTest { assertNotNull(getIfcKey); Type getIfcKeyType = getIfcKey.getReturnType(); assertNotNull(getIfcKeyType); - assertFalse(getIfcKeyType.equals("java.lang.Void")); - assertEquals(getIfcKeyType.getName(), "InterfaceKey"); + assertNotSame("java.lang.Void", getIfcKeyType); + assertEquals("InterfaceKey", getIfcKeyType.getName()); assertNotNull(getHigherLayerIf); Type getHigherLayerIfType = getHigherLayerIf.getReturnType(); assertNotNull(getHigherLayerIfType); - assertFalse(getHigherLayerIfType.equals("java.lang.Void")); - assertEquals(getHigherLayerIfType.getName(), "List"); + assertNotSame("java.lang.Void", getHigherLayerIfType); + assertEquals("List", getHigherLayerIfType.getName()); // NetworkLink final List gtNetworkLinkMethods = gtNetworkLink.getMethodDefinitions(); @@ -172,8 +190,8 @@ public class GeneratedTypesTest { assertNotNull(getIfc); Type getIfcType = getIfc.getReturnType(); assertNotNull(getIfcType); - assertFalse(getIfcType.equals("java.lang.Void")); - assertEquals(getIfcType.getName(), "String"); + assertNotSame("java.lang.Void", getIfcType); + assertEquals("String", getIfcType.getName()); // SourceNode final List gtSourceMethods = gtSource.getMethodDefinitions(); @@ -187,8 +205,8 @@ public class GeneratedTypesTest { assertNotNull(getIdSource); Type getIdType = getIdSource.getReturnType(); assertNotNull(getIdType); - assertFalse(getIdType.equals("java.lang.Void")); - assertEquals(getIdType.getName(), "Uri"); + assertNotSame("java.lang.Void", getIdType); + assertEquals("Uri", getIdType.getName()); // DestinationNode final List gtDestMethods = gtDest.getMethodDefinitions(); @@ -202,8 +220,8 @@ public class GeneratedTypesTest { assertNotNull(getIdDest); Type getIdDestType = getIdDest.getReturnType(); assertNotNull(getIdDestType); - assertFalse(getIdDestType.equals("java.lang.Void")); - assertEquals(getIdDestType.getName(), "Uri"); + assertNotSame("java.lang.Void", getIdDestType); + assertEquals("Uri", getIdDestType.getName()); // Tunnel final List gtTunnelMethods = gtTunnel.getMethodDefinitions(); @@ -217,8 +235,8 @@ public class GeneratedTypesTest { assertNotNull(getTunnelKey); Type getTunnelKeyType = getTunnelKey.getReturnType(); assertNotNull(getTunnelKeyType); - assertFalse(getTunnelKeyType.equals("java.lang.Void")); - assertEquals(getTunnelKeyType.getName(), "TunnelKey"); + assertNotSame("java.lang.Void", getTunnelKeyType); + assertEquals("TunnelKey", getTunnelKeyType.getName()); // TunnelKey final List gtTunnelKeyProps = gtTunnelKey.getProperties(); @@ -232,8 +250,8 @@ public class GeneratedTypesTest { assertNotNull(tunnelId); Type tunnelIdType = tunnelId.getReturnType(); assertNotNull(tunnelIdType); - assertFalse(tunnelIdType.equals("java.lang.Void")); - assertEquals(tunnelIdType.getName(), "Uri"); + assertNotSame("java.lang.Void", tunnelIdType); + assertEquals("Uri", tunnelIdType.getName()); } @Test @@ -256,14 +274,11 @@ public class GeneratedTypesTest { assertEquals(3, simpleContainer.getMethodDefinitions().size()); assertEquals(2, nestedContainer.getMethodDefinitions().size()); - int setFooMethodCounter = 0; int getFooMethodCounter = 0; int getBarMethodCounter = 0; int getNestedContainerCounter = 0; String getFooMethodReturnTypeName = ""; - String setFooMethodInputParamName = ""; - String setFooMethodInputParamTypeName = ""; String getBarMethodReturnTypeName = ""; String getNestedContainerReturnTypeName = ""; for (final MethodSignature method : simpleContainer.getMethodDefinitions()) { @@ -272,13 +287,6 @@ public class GeneratedTypesTest { getFooMethodReturnTypeName = method.getReturnType().getName(); } - if (method.getName().equals("setFoo")) { - setFooMethodCounter++; - final MethodSignature.Parameter param = method.getParameters().get(0); - setFooMethodInputParamName = param.getName(); - setFooMethodInputParamTypeName = param.getType().getName(); - } - if (method.getName().equals("getBar")) { getBarMethodCounter++; getBarMethodReturnTypeName = method.getReturnType().getName(); @@ -290,31 +298,20 @@ public class GeneratedTypesTest { } } - assertEquals(getFooMethodCounter, 1); - assertEquals(getFooMethodReturnTypeName, "Integer"); - - // TODO no setter methods, because 'config' is default true - // assertEquals(setFooMethodCounter, 1); - // assertEquals(setFooMethodInputParamName, "foo"); - // assertEquals(setFooMethodInputParamTypeName, "Integer"); + assertEquals(1, getFooMethodCounter); + assertEquals("Integer", getFooMethodReturnTypeName); - assertEquals(getBarMethodCounter, 1); - assertEquals(getBarMethodReturnTypeName, "String"); + assertEquals(1, getBarMethodCounter); + assertEquals("String", getBarMethodReturnTypeName); - assertEquals(getNestedContainerCounter, 1); - assertEquals(getNestedContainerReturnTypeName, "NestedContainer"); + assertEquals(1, getNestedContainerCounter); + assertEquals("NestedContainer", getNestedContainerReturnTypeName); - setFooMethodCounter = 0; getFooMethodCounter = 0; getBarMethodCounter = 0; - int setBarMethodCounter = 0; getFooMethodReturnTypeName = ""; - setFooMethodInputParamName = ""; - setFooMethodInputParamTypeName = ""; getBarMethodReturnTypeName = ""; - String setBarMethodInputParamName = ""; - String setBarMethodInputParamTypeName = ""; for (final MethodSignature method : nestedContainer.getMethodDefinitions()) { @@ -323,41 +320,17 @@ public class GeneratedTypesTest { getFooMethodReturnTypeName = method.getReturnType().getName(); } - if (method.getName().equals("setFoo")) { - setFooMethodCounter++; - final MethodSignature.Parameter param = method.getParameters().get(0); - setFooMethodInputParamName = param.getName(); - setFooMethodInputParamTypeName = param.getType().getName(); - } - if (method.getName().equals("getBar")) { getBarMethodCounter++; getBarMethodReturnTypeName = method.getReturnType().getName(); } - - if (method.getName().equals("setBar")) { - setBarMethodCounter++; - final MethodSignature.Parameter param = method.getParameters().get(0); - setBarMethodInputParamName = param.getName(); - setBarMethodInputParamTypeName = param.getType().getName(); - } } assertEquals(1, getFooMethodCounter); - assertEquals(getFooMethodReturnTypeName, "Short"); - - // TODO no setter methods, because 'config' is default true - // assertEquals(1, setFooMethodCounter); - // assertEquals(setFooMethodInputParamName, "foo"); - // assertEquals(setFooMethodInputParamTypeName, "Short"); + assertEquals("Short", getFooMethodReturnTypeName); assertEquals(1, getBarMethodCounter); - assertEquals(getBarMethodReturnTypeName, "String"); - - // TODO no setter methods, because 'config' is default true - // assertEquals(1, setBarMethodCounter); - // assertEquals(setBarMethodInputParamName, "bar"); - // assertEquals(setBarMethodInputParamTypeName, "String"); + assertEquals("String", getBarMethodReturnTypeName); } @Test @@ -380,14 +353,11 @@ public class GeneratedTypesTest { assertEquals(3, simpleContainer.getMethodDefinitions().size()); assertEquals(2, nestedContainer.getMethodDefinitions().size()); - int setFooMethodCounter = 0; int getFooMethodCounter = 0; int getBarMethodCounter = 0; int getNestedContainerCounter = 0; String getFooMethodReturnTypeName = ""; - String setFooMethodInputParamName = ""; - String setFooMethodInputParamTypeName = ""; String getBarMethodReturnTypeName = ""; String getNestedContainerReturnTypeName = ""; for (final MethodSignature method : simpleContainer.getMethodDefinitions()) { @@ -396,13 +366,6 @@ public class GeneratedTypesTest { getFooMethodReturnTypeName = method.getReturnType().getName(); } - if (method.getName().equals("setFoo")) { - setFooMethodCounter++; - final MethodSignature.Parameter param = method.getParameters().get(0); - setFooMethodInputParamName = param.getName(); - setFooMethodInputParamTypeName = param.getType().getName(); - } - if (method.getName().equals("getBar")) { getBarMethodCounter++; getBarMethodReturnTypeName = method.getReturnType().getName(); @@ -415,26 +378,18 @@ public class GeneratedTypesTest { } assertEquals(1, getFooMethodCounter); - assertEquals(getFooMethodReturnTypeName, "List"); - - // TODO no setter methods, because 'config' is default true - // assertEquals(1, setFooMethodCounter); - // assertEquals(setFooMethodInputParamName, "foo"); - // assertEquals(setFooMethodInputParamTypeName, "List"); + assertEquals("List", getFooMethodReturnTypeName); assertEquals(1, getBarMethodCounter); - assertEquals(getBarMethodReturnTypeName, "String"); + assertEquals("String", getBarMethodReturnTypeName); assertEquals(1, getNestedContainerCounter); - assertEquals(getNestedContainerReturnTypeName, "NestedContainer"); + assertEquals("NestedContainer", getNestedContainerReturnTypeName); - setFooMethodCounter = 0; getFooMethodCounter = 0; getBarMethodCounter = 0; getFooMethodReturnTypeName = ""; - setFooMethodInputParamName = ""; - setFooMethodInputParamTypeName = ""; getBarMethodReturnTypeName = ""; for (final MethodSignature method : nestedContainer.getMethodDefinitions()) { @@ -443,13 +398,6 @@ public class GeneratedTypesTest { getFooMethodReturnTypeName = method.getReturnType().getName(); } - if (method.getName().equals("setFoo")) { - setFooMethodCounter++; - final MethodSignature.Parameter param = method.getParameters().get(0); - setFooMethodInputParamName = param.getName(); - setFooMethodInputParamTypeName = param.getType().getName(); - } - if (method.getName().equals("getBar")) { getBarMethodCounter++; getBarMethodReturnTypeName = method.getReturnType().getName(); @@ -457,15 +405,10 @@ public class GeneratedTypesTest { } assertEquals(1, getFooMethodCounter); - assertEquals(getFooMethodReturnTypeName, "Short"); - - // TODO no setter methods, because 'config' is default true - // assertEquals(1, setFooMethodCounter); - // assertEquals(setFooMethodInputParamName, "foo"); - // assertEquals(setFooMethodInputParamTypeName, "Short"); + assertEquals("Short", getFooMethodReturnTypeName); assertEquals(1, getBarMethodCounter); - assertEquals(getBarMethodReturnTypeName, "List"); + assertEquals("List", getBarMethodReturnTypeName); } @Test @@ -480,9 +423,6 @@ public class GeneratedTypesTest { assertNotNull(genTypes); assertEquals(6, genTypes.size()); - int genTypesCount = 0; - int genTOsCount = 0; - int listParentContainerMethodsCount = 0; int simpleListMethodsCount = 0; int listChildContainerMethodsCount = 0; @@ -517,7 +457,6 @@ public class GeneratedTypesTest { final GeneratedType genType = (GeneratedType) type; if (genType.getName().equals("ListParentContainer")) { listParentContainerMethodsCount = genType.getMethodDefinitions().size(); - genTypesCount++; } else if (genType.getName().equals("SimpleList")) { simpleListMethodsCount = genType.getMethodDefinitions().size(); final List methods = genType.getMethodDefinitions(); @@ -540,13 +479,10 @@ public class GeneratedTypesTest { getBarMethodCount++; } } - genTypesCount++; } else if (genType.getName().equals("ListChildContainer")) { listChildContainerMethodsCount = genType.getMethodDefinitions().size(); - genTypesCount++; } } else if (type instanceof GeneratedTransferObject) { - genTOsCount++; final GeneratedTransferObject genTO = (GeneratedTransferObject) type; final List properties = genTO.getProperties(); final List hashProps = genTO.getHashCodeIdentifiers(); diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/demo-topology.yang b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/demo-topology.yang index 95de94375f..4fef1cddd2 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/demo-topology.yang +++ b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/demo-topology.yang @@ -1,6 +1,6 @@ module demo-topology { yang-version 1; - namespace ""; + namespace "urn:model.1demo-275topology.4.5.my"; prefix "tp"; organization "OPEN DAYLIGHT"; diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/leafref-test-models/abstract-topology@2013-02-08.yang b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/leafref-test-models/abstract-topology@2013-02-08.yang index 2d6fc26287..be3119255e 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/leafref-test-models/abstract-topology@2013-02-08.yang +++ b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/resources/leafref-test-models/abstract-topology@2013-02-08.yang @@ -57,6 +57,12 @@ module abstract-topology { UNIQUE topology identifier."; } + leaf cond-leafref { + type leafref { + path "/tp:topology/tp:network-nodes/tp:network-node[node-id = 'super-node']"; + } + } + container network-nodes { list network-node { key "node-id"; diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-generator-util/src/main/java/org/opendaylight/controller/binding/generator/util/BindingGeneratorUtil.java b/opendaylight/sal/yang-prototype/code-generator/binding-generator-util/src/main/java/org/opendaylight/controller/binding/generator/util/BindingGeneratorUtil.java index a394edd906..0c4683ed03 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-generator-util/src/main/java/org/opendaylight/controller/binding/generator/util/BindingGeneratorUtil.java +++ b/opendaylight/sal/yang-prototype/code-generator/binding-generator-util/src/main/java/org/opendaylight/controller/binding/generator/util/BindingGeneratorUtil.java @@ -30,8 +30,11 @@ public final class BindingGeneratorUtil { if (packNameParts != null) { final StringBuilder builder = new StringBuilder(); for (int i = 0; i < packNameParts.length; ++i) { - if (JAVA_RESERVED_WORDS.contains(packNameParts[i])) { - packNameParts[i] = "_" + packNameParts[i]; + final String packNamePart = packNameParts[i]; + if (Character.isDigit(packNamePart.charAt(0))) { + packNameParts[i] = "_" + packNamePart; + } else if (JAVA_RESERVED_WORDS.contains(packNamePart)) { + packNameParts[i] = "_" + packNamePart; } if (i > 0) { builder.append("."); diff --git a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/pom.xml b/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/pom.xml deleted file mode 100644 index d4c5b05731..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - 4.0.0 - org.opendaylight.controller - code-generator-demo - 1.0 - jar - - - - org.antlr - antlr4 - 4.0 - - - org.opendaylight.controller - binding-generator-impl - - - org.opendaylight.controller - binding-java-api-generator - - - - - - - maven-assembly-plugin - 2.4 - - - jar-with-dependencies - - - - org.opendaylight.controller.yang.Demo - - - - - - make-assembly - package - - single - - - - - - - - diff --git a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/java/org/opendaylight/controller/yang/Demo.java b/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/java/org/opendaylight/controller/yang/Demo.java deleted file mode 100644 index ee548876d0..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/java/org/opendaylight/controller/yang/Demo.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2013 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.controller.yang; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.opendaylight.controller.sal.binding.generator.api.BindingGenerator; -import org.opendaylight.controller.sal.binding.generator.impl.BindingGeneratorImpl; -import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject; -import org.opendaylight.controller.sal.binding.model.api.GeneratedType; -import org.opendaylight.controller.sal.binding.model.api.Type; -import org.opendaylight.controller.sal.java.api.generator.GeneratorJavaFile; -import org.opendaylight.controller.yang.model.api.Module; -import org.opendaylight.controller.yang.model.api.SchemaContext; -import org.opendaylight.controller.yang.parser.impl.YangParserImpl; - -public class Demo { - private static final String ERR_MSG = "2 parameters expected: 1. -f=, 2. -o="; - - public static void main(String[] args) throws Exception { - if (args.length != 2) { - System.err.println(ERR_MSG); - return; - } - - String inputFilesDir = null; - String outputFilesDir = null; - if (args[0].startsWith("-f=")) { - inputFilesDir = args[0].substring(3); - } else { - System.err.println("Missing input-folder declaration (-f=)"); - } - - if (args[1].startsWith("-o=")) { - outputFilesDir = args[1].substring(3); - } else { - System.err.println("Missing output-folder declaration (-o=)"); - } - - File resourceDir = new File(inputFilesDir); - if (!resourceDir.exists()) { - throw new IllegalArgumentException( - "Specified input-folder does not exists: " - + resourceDir.getAbsolutePath()); - } - - final File outputFolder = new File(outputFilesDir); - if (!outputFolder.exists()) { - outputFolder.mkdirs(); - } - - String[] dirList = resourceDir.list(); - List inputFiles = new ArrayList(); - for (String fileName : dirList) { - inputFiles.add(new File(resourceDir, fileName)); - } - - final YangParserImpl parser = new YangParserImpl(); - final BindingGenerator bindingGenerator = new BindingGeneratorImpl(); - final Set modulesToBuild = parser.parseYangModels(inputFiles); - - final SchemaContext context = parser - .resolveSchemaContext(modulesToBuild); - final List types = bindingGenerator.generateTypes(context); - final Set typesToGenerate = new HashSet(); - final Set tosToGenerate = new HashSet(); - for (Type type : types) { - if (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject)) { - typesToGenerate.add((GeneratedType) type); - } - - if (type instanceof GeneratedTransferObject) { - tosToGenerate.add((GeneratedTransferObject) type); - } else if (type instanceof GeneratedType) { - typesToGenerate.add((GeneratedType) type); - } - } - - final GeneratorJavaFile generator = new GeneratorJavaFile(typesToGenerate, tosToGenerate); - - generator.generateToFile(outputFolder); - System.out.println("Modules built: " + modulesToBuild.size()); - } -} diff --git a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo-topology.yang b/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo-topology.yang deleted file mode 100644 index 303edc295d..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo-topology.yang +++ /dev/null @@ -1,223 +0,0 @@ -module demo-topology { - yang-version 1; - namespace "urn:demo.simple-topology"; - prefix "tp"; - import simple-list-demo { prefix "simple"; revision-date 2008-01-01; } - import controller-network {prefix "cn";} - import mount {prefix "mnt";} - - organization "OPEN DAYLIGHT"; - contact "http://www.opendaylight.org/"; - - description " - This module contains the definitions of elements that creates network - topology i.e. definition of network nodes and links. This module is - not designed to be used solely for network representation. This module - SHOULD be used as base module in defining the network topology. - "; - - revision "2013-02-08"{ - reference " WILL BE DEFINED LATER"; - } - - - - - - deviation /base:system/base:user/base:type { - deviate add { - default "admin"; // new users are 'admin' by default - } - } - - deviation /base:system/base:name-server { - deviate replace { - max-elements 3; - } - } - - deviation "/base:system" { - deviate delete { - must "daytime or time"; - } - } - - - - - - - grouping target { - status "current"; - leaf address { - type inet:ip-address; - description "Target IP address"; - } - leaf port { - type inet:port-number; - description "Target port number"; - } - } - - augment "/cn:network/cn:topologies/cn:topology" { - container prefixes { - container "prefix" { - leaf id { - type string; - - description ""; - } - - leaf-list advertising-node-id { - type cn:node-ref; - - description ""; - } - } - } - mnt:mountpoint point { - mnt:target-ref target; - - } - } - - container peer { - container destination { - uses target; - } - } - - container topology { - - leaf ifType { - type enumeration { - enum ethernet; - enum atm; - } - } - leaf ifMTU { - type uint32; - } - must "ifType != 'ethernet' or " + - "(ifType = 'ethernet' and ifMTU = 1500)" { - error-message "An ethernet MTU must be 1500"; - } - - presence "test-presence"; - - description " - This is the model of abstract topology which contains only Network - Nodes and Network Links. Each topology MUST be identified by - unique topology-id for reason that the store could contain many - topologies. - "; - - leaf topology-id { - type string; - description " - It is presumed that datastore will contain many topologies. To - distinguish between topologies it is vital to have UNIQUE - topology identifier. - "; - } - - container network-nodes { - list network-node { - ordered-by system; - description "The list of network nodes defined for topology."; - - key "node-id"; - - leaf node-id { - type string; - description "The Topology identifier of network-node."; - } - - list network-interface { - key "interface-id"; - - leaf interface-id { - type uint8; - } - - leaf interface-address { - type string; - } - } - - container node-attributes { - description " - Additional attributes that can Network Node contains. - "; - - leaf geo-latitude { - type decimal64 { - fraction-digits 2; - } - config true; - } - - leaf geo-longitude { - type decimal64 { - fraction-digits 2; - } - config true; - } - } - } - } - - container network-links { - list network-link { - description " - The Network Link which is defined by Local (Source) and - Remote (Destination) Network Nodes. Every link MUST be - defined either by identifier and his local and remote - Network Nodes (in real applications it is common that many - links are originated from one node and end up in same - remote node). To ensure that we would always know to - distinguish between links, every link SHOULD have - identifier. - "; - key "link-id"; - - leaf link-id { - type string; - description ""; - } - - container source { - leaf node-id { - type string; - description "Source node identifier."; - } - } - - container destination { - leaf node-id { - type string; - description "Destination node identifier."; - } - } - - container link-attributes { - description "Aditional attributes that can Network Link contains."; - } - } - } - } - - rpc activate-software-image { - input { - leaf image-name { - type string; - } - } - output { - leaf status { - type string; - } - } - } - -} diff --git a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types1.yang b/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types1.yang deleted file mode 100644 index 102529858b..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types1.yang +++ /dev/null @@ -1,80 +0,0 @@ -module types1 { - yang-version 1; - namespace "urn:simple.container.demo"; - prefix "t1"; - - - organization "Cisco"; - - contact "WILL-BE-DEFINED-LATER"; - - - leaf mybits { - type bits { - bit disable-nagle { - position 0; - } - bit auto-sense-speed { - position 1; - } - bit 10-Mb-only { - position 2; - } - } - default "auto-sense-speed"; - } - - container interfaces { - list ifEntry { - key "ifIndex"; - - leaf ifIndex { - type uint32; - } - leaf ifDescr { - type string; - } - leaf ifType { - type uint8; - } - leaf ifMtu { - type int32; - } - } - } - - - container topology { - leaf name { - type string; - } - } - - - - - - - -// typedef my-string { -// type string { -// length "0..4"; -// pattern "[0-9a-fA-F]*"; -// } -// } - - -// leaf completed { -// type types2:percent; -// } - -// leaf testleaf { -// type data:my-base-int32-type; -// } - -// leaf-list domain-search { -// type string; -// description "List of domain names to search"; -// } - -} diff --git a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types2.yang b/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types2.yang deleted file mode 100644 index a056bdb2e9..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types2.yang +++ /dev/null @@ -1,35 +0,0 @@ -module types2 { - yang-version 1; - namespace "urn:simple.types.data.demo"; - prefix "t2"; - - import types1 { - prefix "t1"; - } - - organization "Cisco"; - - contact "WILL-BE-DEFINED-LATER"; - - description "This is types-data test description"; - - revision "2013-02-27" { - reference " WILL BE DEFINED LATER"; - } - - - augment "/t1:interfaces/t1:ifEntry" { - when "t1:ifType='ds0'"; - leaf ds0ChannelNumber { - type string; - } - } - - typedef my-leaf-ref { - type leafref { - path "/t1:topology/t1:name"; - } - description "This type is used for leafs that reference network node instance."; - } - -} diff --git a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types3.yang b/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types3.yang deleted file mode 100644 index 0d09259f3e..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/demo/types3.yang +++ /dev/null @@ -1,35 +0,0 @@ -module types3 { - yang-version 1; - namespace "urn:simple.types3.data.demo"; - prefix "scd"; - - organization "Cisco"; - - contact "WILL-BE-DEFINED-LATER"; - - description "This is types-data test description"; - - revision "2013-02-27" { - reference " WILL BE DEFINED LATER"; - } - - typedef my-decimal { - type decimal64 { - fraction-digits 2; - } - } - - typedef my-base-int32-type { - type int32 { - range "0..32"; - } - } - - typedef percent { - type uint8 { - range "0 .. 100"; - } - description "Percentage"; - } - -} diff --git a/opendaylight/sal/yang-prototype/code-generator/samples/maven-code-gen-sample/src/main/yang/controller-network-ne.yang b/opendaylight/sal/yang-prototype/code-generator/samples/maven-code-gen-sample/src/main/yang/controller-network-ne.yang index 8b576c3ce9..ca8507f9f4 100644 --- a/opendaylight/sal/yang-prototype/code-generator/samples/maven-code-gen-sample/src/main/yang/controller-network-ne.yang +++ b/opendaylight/sal/yang-prototype/code-generator/samples/maven-code-gen-sample/src/main/yang/controller-network-ne.yang @@ -14,7 +14,7 @@ module controller-openflow-ne { augment "/cn:network/cn:network-elements/cn:network-element" { - container flow-tables { + container flow-tables2 { list flow-table { key "id"; diff --git a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/test-topology.yang b/opendaylight/sal/yang-prototype/code-generator/samples/maven-code-gen-sample/src/main/yang/demo-topology.yang similarity index 66% rename from opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/test-topology.yang rename to opendaylight/sal/yang-prototype/code-generator/samples/maven-code-gen-sample/src/main/yang/demo-topology.yang index 797ab2ced2..4fef1cddd2 100644 --- a/opendaylight/sal/yang-prototype/code-generator/code-generator-demo/src/main/resources/test-topology.yang +++ b/opendaylight/sal/yang-prototype/code-generator/samples/maven-code-gen-sample/src/main/yang/demo-topology.yang @@ -1,13 +1,9 @@ -// vi: set smarttab sw=4 tabstop=4: -module abstract-topology { +module demo-topology { yang-version 1; - namespace "pre:simple.test.demo"; + namespace "urn:model.1demo-275topology.4.5.my"; prefix "tp"; - import ietf-inet-types { prefix "inet"; } - import abstract-prefixes { prefix "abs-pref"; } - - organization "OPEN DAYLIGHT"; + organization "OPEN DAYLIGHT"; contact "http://www.opendaylight.org/"; description " @@ -16,30 +12,9 @@ module abstract-topology { not designed to be used solely for network representation. This module SHOULD be used as base module in defining the network topology. "; - - revision "2012-02-08" { - reference " WILL BE DEFINED LATER"; - } - - typedef topology-id-ref { - type leafref { - path "/tp:topology/tp:topology-id"; - } - description "This type is used for leafs that reference topology identifier instance."; - } - typedef network-node-id-ref { - type leafref { - path "/tp:topology/tp:network-nodes/tp:network-node/tp:node-id"; - } - description "This type is used for leafs that reference network node instance."; - } - - typedef link-id-ref { - type leafref { - path "/tp:topology/tp:network-links/tp:network-link/tp:link-id"; - } - description "This type is used for leafs that reference network link instance."; + revision "2013-02-08"{ + reference " WILL BE DEFINED LATER"; } container topology { @@ -51,7 +26,7 @@ module abstract-topology { "; leaf topology-id { - type inet:uri; + type string; description " It is presumed that datastore will contain many topologies. To distinguish between topologies it is vital to have UNIQUE @@ -66,14 +41,40 @@ module abstract-topology { key "node-id"; leaf node-id { - type inet:uri; + type string; description "The Topology identifier of network-node."; } - - container attributes { + + list network-interface { + key "interface-id"; + + leaf interface-id { + type uint8; + } + + leaf interface-address { + type string; + } + } + + container node-attributes { description " Additional attributes that can Network Node contains. "; + + leaf geo-latitude { + type decimal64 { + fraction-digits 2; + } + config true; + } + + leaf geo-longitude { + type decimal64 { + fraction-digits 2; + } + config true; + } } } } @@ -93,30 +94,28 @@ module abstract-topology { key "link-id"; leaf link-id { - type inet:uri; + type string; description ""; } container source { leaf node-id { - type node-id-ref; + type string; description "Source node identifier."; } } container destination { leaf node-id { - type node-id-ref; + type string; description "Destination node identifier."; } } - container attributes { + container link-attributes { description "Aditional attributes that can Network Link contains."; } } } } - - //TODO: add base operations -} +} \ No newline at end of file diff --git a/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/SchemaContextUtil.java b/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/SchemaContextUtil.java index 44ef804e2c..1d702c26d8 100644 --- a/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/SchemaContextUtil.java +++ b/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/SchemaContextUtil.java @@ -16,99 +16,254 @@ import java.util.Set; import org.opendaylight.controller.yang.common.QName; import org.opendaylight.controller.yang.model.api.*; +/** + * The Schema Context Util contains support methods for searching through Schema Context modules for specified schema + * nodes via Schema Path or Revision Aware XPath. The Schema Context Util is designed as mixin, + * so it is not instantiable. + * + * @author Lukas Sedlak + */ public final class SchemaContextUtil { private SchemaContextUtil() { } + /** + * Method attempts to find DataSchemaNode in Schema Context via specified Schema Path. The returned + * DataSchemaNode from method will be the node at the end of the SchemaPath. If the DataSchemaNode is not present + * in the Schema Context the method will return null. + *
+ * In case that Schema Context or Schema Path are not specified correctly (i.e. contains null + * values) the method will return IllegalArgumentException. + * + * @throws IllegalArgumentException + * + * @param context + * Schema Context + * @param schemaPath + * Schema Path to search for + * @return DataSchemaNode from the end of the Schema Path or + * null if the Node is not present. + */ public static DataSchemaNode findDataSchemaNode(final SchemaContext context, final SchemaPath schemaPath) { - if (schemaPath != null) { - final Module module = resolveModuleFromSchemaPath(context, schemaPath); - final Queue prefixedPath = new LinkedList<>(schemaPath.getPath()); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (schemaPath == null) { + throw new IllegalArgumentException("Schema Path reference cannot be NULL"); + } - if ((module != null) && (prefixedPath != null)) { - return findSchemaNodeForGivenPath(context, module, prefixedPath); - } + final Module module = resolveModuleFromSchemaPath(context, schemaPath); + final Queue prefixedPath = new LinkedList<>(schemaPath.getPath()); + + if ((module != null) && (prefixedPath != null)) { + return findSchemaNodeForGivenPath(context, module, prefixedPath); } return null; } + /** + * Method attempts to find DataSchemaNode inside of provided Schema Context and Yang Module accordingly to + * Non-conditional Revision Aware XPath. The specified Module MUST be present in Schema Context otherwise the + * operation would fail and return null. + *
+ * The Revision Aware XPath MUST be specified WITHOUT the conditional statement (i.e. without [cond]) in path, + * because in this state the Schema Context is completely unaware of data state and will be not able to properly + * resolve XPath. If the XPath contains condition the method will return IllegalArgumentException. + *
+ * In case that Schema Context or Module or Revision Aware XPath contains null references the method + * will throw IllegalArgumentException + *
+ * If the Revision Aware XPath is correct and desired Data Schema Node is present in Yang module or in depending + * module in Schema Context the method will return specified Data Schema Node, otherwise the operation will fail + * and method will return null. + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param module Yang Module + * @param nonCondXPath Non Conditional Revision Aware XPath + * @return Returns Data Schema Node for specified Schema Context for given Non-conditional Revision Aware XPath, + * or null if the DataSchemaNode is not present in Schema Context. + */ public static DataSchemaNode findDataSchemaNode(final SchemaContext context, final Module module, final RevisionAwareXPath nonCondXPath) { - if (nonCondXPath != null) { - final String strXPath = nonCondXPath.toString(); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (nonCondXPath == null) { + throw new IllegalArgumentException("Non Conditional Revision Aware XPath cannot be NULL!"); + } - if (strXPath != null) { - if (strXPath.matches(".*//[.* | .*//].*")) { - // TODO: function to escape conditions in path - } - if (nonCondXPath.isAbsolute()) { - final Queue qnamedPath = xpathToQNamePath(context, module, strXPath); - if (qnamedPath != null) { - final DataSchemaNode dataNode = findSchemaNodeForGivenPath(context, module, qnamedPath); - return dataNode; - } + final String strXPath = nonCondXPath.toString(); + if (strXPath != null) { + if (strXPath.contains("[")) { + throw new IllegalArgumentException("Revision Aware XPath cannot contains condition!"); + } + if (nonCondXPath.isAbsolute()) { + final Queue qnamedPath = xpathToQNamePath(context, module, strXPath); + if (qnamedPath != null) { + final DataSchemaNode dataNode = findSchemaNodeForGivenPath(context, module, qnamedPath); + return dataNode; } } } return null; } + /** + * Method attempts to find DataSchemaNode inside of provided Schema Context and Yang Module accordingly to + * Non-conditional relative Revision Aware XPath. The specified Module MUST be present in Schema Context otherwise + * the operation would fail and return null. + *
+ * The relative Revision Aware XPath MUST be specified WITHOUT the conditional statement (i.e. without [cond]) in + * path, because in this state the Schema Context is completely unaware of data state and will be not able to + * properly resolve XPath. If the XPath contains condition the method will return IllegalArgumentException. + *
+ * The Actual Schema Node MUST be specified correctly because from this Schema Node will search starts. If the + * Actual Schema Node is not correct the operation will simply fail, because it will be unable to find desired + * DataSchemaNode. + *
+ * In case that Schema Context or Module or Actual Schema Node or relative Revision Aware XPath contains + * null references the method will throw IllegalArgumentException + *
+ * If the Revision Aware XPath doesn't have flag isAbsolute == false the method will + * throw IllegalArgumentException. + *
+ * If the relative Revision Aware XPath is correct and desired Data Schema Node is present in Yang module or in + * depending module in Schema Context the method will return specified Data Schema Node, + * otherwise the operation will fail + * and method will return null. + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param module Yang Module + * @param actualSchemaNode Actual Schema Node + * @param relativeXPath Relative Non Conditional Revision Aware XPath + * @return DataSchemaNode if is present in specified Schema Context for given relative Revision Aware XPath, + * otherwise will return null. + */ public static DataSchemaNode findDataSchemaNodeForRelativeXPath(final SchemaContext context, final Module module, final SchemaNode actualSchemaNode, final RevisionAwareXPath relativeXPath) { - if ((actualSchemaNode != null) && (relativeXPath != null) && !relativeXPath.isAbsolute()) { + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (actualSchemaNode == null) { + throw new IllegalArgumentException("Actual Schema Node reference cannot be NULL!"); + } + if (relativeXPath == null) { + throw new IllegalArgumentException("Non Conditional Revision Aware XPath cannot be NULL!"); + } + if (relativeXPath.isAbsolute()) { + throw new IllegalArgumentException("Revision Aware XPath MUST be relative i.e. MUST contains ../, " + + "for non relative Revision Aware XPath use findDataSchemaNode method!"); + } - final SchemaPath actualNodePath = actualSchemaNode.getPath(); - if (actualNodePath != null) { - final Queue qnamePath = resolveRelativeXPath(context, module, relativeXPath, actualNodePath); + final SchemaPath actualNodePath = actualSchemaNode.getPath(); + if (actualNodePath != null) { + final Queue qnamePath = resolveRelativeXPath(context, module, relativeXPath, actualNodePath); - if (qnamePath != null) { - final DataSchemaNode dataNode = findSchemaNodeForGivenPath(context, module, qnamePath); - return dataNode; - } + if (qnamePath != null) { + final DataSchemaNode dataNode = findSchemaNodeForGivenPath(context, module, qnamePath); + return dataNode; } } - return null; } + /** + * Retrieve information from Schema Path and returns the module reference to which Schema Node belongs. The + * search for correct Module is based on namespace within the last item in Schema Path. If schema context + * contains module with namespace specified in last item of Schema Path, then operation will returns Module + * reference, otherwise returns null + *
+ * If Schema Context or Schema Node contains null references the method will throw IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param schemaPath Schema Path + * @return Module reference for given Schema Path if module is present in Schema Context, + * otherwise returns null + */ private static Module resolveModuleFromSchemaPath(final SchemaContext context, final SchemaPath schemaPath) { - if ((schemaPath != null) && (schemaPath.getPath() != null)) { - final List path = schemaPath.getPath(); - if (!path.isEmpty()) { - final QName qname = path.get(path.size() - 1); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (schemaPath == null) { + throw new IllegalArgumentException("Schema Path reference cannot be NULL"); + } - if ((qname != null) && (qname.getNamespace() != null)) { - return context.findModuleByNamespace(qname.getNamespace()); - } + final List path = schemaPath.getPath(); + if (!path.isEmpty()) { + final QName qname = path.get(path.size() - 1); + + if ((qname != null) && (qname.getNamespace() != null)) { + return context.findModuleByNamespace(qname.getNamespace()); } } + return null; } + /** + * Returns the Yang Module from specified Schema Context in which the TypeDefinition is declared. If the + * TypeDefinition si not present in Schema Context then the method will return null + * + * If Schema Context or TypeDefinition contains null references the method will throw IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param type Type Definition + * @return Yang Module in which the TypeDefinition is declared, if is not present, returns null. + */ public static Module findParentModuleForTypeDefinition(final SchemaContext context, final TypeDefinition type) { final SchemaPath schemaPath = type.getPath(); - if ((schemaPath != null) && (schemaPath.getPath() != null)) { - if (type instanceof ExtendedType) { - List path = schemaPath.getPath(); - final QName qname = path.get(path.size() - 1); - - if ((qname != null) && (qname.getNamespace() != null)) { - return context.findModuleByNamespace(qname.getNamespace()); - } - } else { - List path = schemaPath.getPath(); - final QName qname = path.get(path.size() - 2); + if (schemaPath == null) { + throw new IllegalArgumentException("Schema Path reference cannot be NULL"); + } + final List qnamedPath = schemaPath.getPath(); + if (qnamedPath == null || qnamedPath.isEmpty()) { + throw new IllegalStateException("Schema Path contains invalid state of path parts." + + "The Schema Path MUST contain at least ONE QName which defines namespace and Local name" + + "of path."); + } - if ((qname != null) && (qname.getNamespace() != null)) { - return context.findModuleByNamespace(qname.getNamespace()); - } + if (type instanceof ExtendedType) { + final QName qname = qnamedPath.get(qnamedPath.size() - 1); + if ((qname != null) && (qname.getNamespace() != null)) { + return context.findModuleByNamespace(qname.getNamespace()); + } + } else { + final QName qname = qnamedPath.get(qnamedPath.size() - 2); + if ((qname != null) && (qname.getNamespace() != null)) { + return context.findModuleByNamespace(qname.getNamespace()); } - } return null; } + /** + * Returns parent Yang Module for specified Schema Context in which Schema Node is declared. If the Schema Node + * is not present in Schema Context the operation will return null. + *
+ * If Schema Context or Schema Node contains null references the method will throw IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param schemaNode Schema Node + * @return Yang Module for specified Schema Context and Schema Node, if Schema Node is NOT present, + * the method will returns null + */ public static Module findParentModule(final SchemaContext context, final SchemaNode schemaNode) { if (context == null) { throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); @@ -132,120 +287,246 @@ public final class SchemaContextUtil { return context.findModuleByNamespace(qname.getNamespace()); } + /** + * Method will attempt to find DataSchemaNode from specified Module and Queue of QNames through the Schema + * Context. The QNamed path could be defined across multiple modules in Schema Context so the method is called + * recursively. If the QNamed path contains QNames that are not part of any Module or Schema Context Path the + * operation will fail and returns null + *
+ * If Schema Context, Module or Queue of QNames refers to null values, + * the method will throws IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param module Yang Module + * @param qnamedPath Queue of QNames + * @return DataSchemaNode if is present in Module(s) for specified Schema Context and given QNamed Path, + * otherwise will return null. + */ private static DataSchemaNode findSchemaNodeForGivenPath(final SchemaContext context, final Module module, final Queue qnamedPath) { - if ((module != null) && (module.getNamespace() != null) && (qnamedPath != null)) { - DataNodeContainer nextNode = module; - final URI moduleNamespace = module.getNamespace(); - - QName childNodeQName; - DataSchemaNode schemaNode = null; - while ((nextNode != null) && !qnamedPath.isEmpty()) { - childNodeQName = qnamedPath.peek(); - if (childNodeQName != null) { - final URI childNodeNamespace = childNodeQName.getNamespace(); - - schemaNode = nextNode.getDataChildByName(childNodeQName); - if (schemaNode != null) { - if (schemaNode instanceof ContainerSchemaNode) { - nextNode = (ContainerSchemaNode) schemaNode; - } else if (schemaNode instanceof ListSchemaNode) { - nextNode = (ListSchemaNode) schemaNode; - } else if (schemaNode instanceof ChoiceNode) { - final ChoiceNode choice = (ChoiceNode) schemaNode; - qnamedPath.poll(); - if (!qnamedPath.isEmpty()) { - childNodeQName = qnamedPath.peek(); - nextNode = choice.getCaseNodeByName(childNodeQName); - schemaNode = (DataSchemaNode)nextNode; - } - } else { - nextNode = null; + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (module.getNamespace() == null) { + throw new IllegalArgumentException("Namespace for Module cannot contains NULL reference!"); + } + if (qnamedPath == null || qnamedPath.isEmpty()) { + throw new IllegalStateException("Schema Path contains invalid state of path parts." + + "The Schema Path MUST contain at least ONE QName which defines namespace and Local name" + + "of path."); + } + + DataNodeContainer nextNode = module; + final URI moduleNamespace = module.getNamespace(); + + QName childNodeQName; + DataSchemaNode schemaNode = null; + while ((nextNode != null) && !qnamedPath.isEmpty()) { + childNodeQName = qnamedPath.peek(); + if (childNodeQName != null) { + final URI childNodeNamespace = childNodeQName.getNamespace(); + + schemaNode = nextNode.getDataChildByName(childNodeQName); + if (schemaNode != null) { + if (schemaNode instanceof ContainerSchemaNode) { + nextNode = (ContainerSchemaNode) schemaNode; + } else if (schemaNode instanceof ListSchemaNode) { + nextNode = (ListSchemaNode) schemaNode; + } else if (schemaNode instanceof ChoiceNode) { + final ChoiceNode choice = (ChoiceNode) schemaNode; + qnamedPath.poll(); + if (!qnamedPath.isEmpty()) { + childNodeQName = qnamedPath.peek(); + nextNode = choice.getCaseNodeByName(childNodeQName); + schemaNode = (DataSchemaNode) nextNode; } - } else if (!childNodeNamespace.equals(moduleNamespace)) { - final Module nextModule = context.findModuleByNamespace(childNodeNamespace); - schemaNode = findSchemaNodeForGivenPath(context, nextModule, qnamedPath); - return schemaNode; + } else { + nextNode = null; } - qnamedPath.poll(); + } else if (!childNodeNamespace.equals(moduleNamespace)) { + final Module nextModule = context.findModuleByNamespace(childNodeNamespace); + schemaNode = findSchemaNodeForGivenPath(context, nextModule, qnamedPath); + return schemaNode; } + qnamedPath.poll(); } - return schemaNode; } - return null; + return schemaNode; } + /** + * Transforms string representation of XPath to Queue of QNames. The XPath is split by "/" and for each part of + * XPath is assigned correct module in Schema Path. + *
+ * If Schema Context, Parent Module or XPath string contains null values, + * the method will throws IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param parentModule Parent Module + * @param xpath XPath String + * @return + */ private static Queue xpathToQNamePath(final SchemaContext context, final Module parentModule, final String xpath) { - final Queue path = new LinkedList<>(); - if (xpath != null) { - final String[] prefixedPath = xpath.split("/"); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (parentModule == null) { + throw new IllegalArgumentException("Parent Module reference cannot be NULL!"); + } + if (xpath == null) { + throw new IllegalArgumentException("XPath string reference cannot be NULL!"); + } - for (int i = 0; i < prefixedPath.length; ++i) { - if (!prefixedPath[i].isEmpty()) { - path.add(stringPathPartToQName(context, parentModule, prefixedPath[i])); - } + final Queue path = new LinkedList<>(); + final String[] prefixedPath = xpath.split("/"); + for (int i = 0; i < prefixedPath.length; ++i) { + if (!prefixedPath[i].isEmpty()) { + path.add(stringPathPartToQName(context, parentModule, prefixedPath[i])); } } return path; } + /** + * Transforms part of Prefixed Path as java String to QName. + *
+ * If the string contains module prefix separated by ":" (i.e. mod:container) this module is provided from from + * Parent Module list of imports. If the Prefixed module is present in Schema Context the QName can be + * constructed. + *
+ * If the Prefixed Path Part does not contains prefix the Parent's Module namespace is taken for construction of + * QName. + *
+ * If Schema Context, Parent Module or Prefixed Path Part refers to null the method will throw + * IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param parentModule Parent Module + * @param prefixedPathPart Prefixed Path Part string + * @return QName from prefixed Path Part String. + */ private static QName stringPathPartToQName(final SchemaContext context, final Module parentModule, final String prefixedPathPart) { - if (parentModule != null && prefixedPathPart != null) { - if (prefixedPathPart.contains(":")) { - final String[] prefixedName = prefixedPathPart.split(":"); - final Module module = resolveModuleForPrefix(context, parentModule, prefixedName[0]); - if (module != null) { - return new QName(module.getNamespace(), module.getRevision(), prefixedName[1]); - } - } else { - return new QName(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (parentModule == null) { + throw new IllegalArgumentException("Parent Module reference cannot be NULL!"); + } + if (prefixedPathPart == null) { + throw new IllegalArgumentException("Prefixed Path Part cannot be NULL!"); + } + + if (prefixedPathPart.contains(":")) { + final String[] prefixedName = prefixedPathPart.split(":"); + final Module module = resolveModuleForPrefix(context, parentModule, prefixedName[0]); + if (module != null) { + return new QName(module.getNamespace(), module.getRevision(), prefixedName[1]); } + } else { + return new QName(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart); } return null; } + /** + * Method will attempt to resolve and provide Module reference for specified module prefix. Each Yang module + * could contains multiple imports which MUST be associated with corresponding module prefix. The method simply + * looks into module imports and returns the module that is bounded with specified prefix. If the prefix is not + * present in module or the prefixed module is not present in specified Schema Context, + * the method will return null. + *
+ * If String prefix is the same as prefix of the specified Module the reference to this module is returned. + *
+ * If Schema Context, Module or Prefix are referring to null the method will return + * IllegalArgumentException + * + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param module Yang Module + * @param prefix Module Prefix + * @return Module for given prefix in specified Schema Context if is present, otherwise returns null + */ private static Module resolveModuleForPrefix(final SchemaContext context, final Module module, final String prefix) { - if ((module != null) && (prefix != null)) { - if (prefix.equals(module.getPrefix())) { - return module; - } + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (prefix == null) { + throw new IllegalArgumentException("Prefix string cannot be NULL!"); + } - final Set imports = module.getImports(); + if (prefix.equals(module.getPrefix())) { + return module; + } - for (final ModuleImport mi : imports) { - if (prefix.equals(mi.getPrefix())) { - return context.findModuleByName(mi.getModuleName(), mi.getRevision()); - } + final Set imports = module.getImports(); + for (final ModuleImport mi : imports) { + if (prefix.equals(mi.getPrefix())) { + return context.findModuleByName(mi.getModuleName(), mi.getRevision()); } } return null; } + /** + * @throws IllegalArgumentException + * + * @param context Schema Context + * @param module Yang Module + * @param relativeXPath Non conditional Revision Aware Relative XPath + * @param leafrefSchemaPath Schema Path for Leafref + * @return + */ private static Queue resolveRelativeXPath(final SchemaContext context, final Module module, final RevisionAwareXPath relativeXPath, final SchemaPath leafrefSchemaPath) { final Queue absolutePath = new LinkedList<>(); + if (context == null) { + throw new IllegalArgumentException("Schema Context reference cannot be NULL!"); + } + if (module == null) { + throw new IllegalArgumentException("Module reference cannot be NULL!"); + } + if (relativeXPath == null) { + throw new IllegalArgumentException("Non Conditional Revision Aware XPath cannot be NULL!"); + } + if (relativeXPath.isAbsolute()) { + throw new IllegalArgumentException("Revision Aware XPath MUST be relative i.e. MUST contains ../, " + + "for non relative Revision Aware XPath use findDataSchemaNode method!"); + } + if (leafrefSchemaPath == null) { + throw new IllegalArgumentException("Schema Path reference for Leafref cannot be NULL!"); + } - if ((module != null) && (relativeXPath != null) && !relativeXPath.isAbsolute() && (leafrefSchemaPath != null)) { - final String strXPath = relativeXPath.toString(); - if (strXPath != null) { - final String[] xpaths = strXPath.split("/"); - - if (xpaths != null) { - int colCount = 0; - while (xpaths[colCount].contains("..")) { - ++colCount; + final String strXPath = relativeXPath.toString(); + if (strXPath != null) { + final String[] xpaths = strXPath.split("/"); + if (xpaths != null) { + int colCount = 0; + while (xpaths[colCount].contains("..")) { + ++colCount; + } + final List path = leafrefSchemaPath.getPath(); + if (path != null) { + int lenght = path.size() - colCount - 1; + for (int i = 0; i < lenght; ++i) { + absolutePath.add(path.get(i)); } - final List path = leafrefSchemaPath.getPath(); - if (path != null) { - int lenght = path.size() - colCount - 1; - for (int i = 0; i < lenght; ++i) { - absolutePath.add(path.get(i)); - } - for (int i = colCount; i < xpaths.length; ++i) { - absolutePath.add(stringPathPartToQName(context, module, xpaths[i])); - } + for (int i = colCount; i < xpaths.length; ++i) { + absolutePath.add(stringPathPartToQName(context, module, xpaths[i])); } } } -- 2.36.6